1 /* 2 * Copyright 2001-2007, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Tyler Dauwalder 7 */ 8 9 10 #include "RegistrarThreadManager.h" 11 12 #include <RegistrarDefs.h> 13 14 #include <stdio.h> 15 16 #include "RegistrarThread.h" 17 18 19 //#define DBG(x) x 20 #define DBG(x) 21 #define OUT printf 22 23 using namespace BPrivate; 24 25 /*! 26 \class RegistrarThreadManager 27 \brief RegistrarThreadManager is the master of all threads spawned by the registrar 28 29 */ 30 31 //! Creates a new RegistrarThreadManager object 32 RegistrarThreadManager::RegistrarThreadManager() 33 : fThreadCount(0) 34 { 35 } 36 37 // destructor 38 /*! \brief Destroys the RegistrarThreadManager object, killing and deleting any still 39 running threads. 40 */ 41 RegistrarThreadManager::~RegistrarThreadManager() 42 { 43 KillThreads(); 44 } 45 46 // MessageReceived 47 /*! \brief Handles \c B_REG_MIME_UPDATE_THREAD_FINISHED messages, passing on all others. 48 49 Each \c B_REG_MIME_UPDATE_THREAD_FINISHED message triggers a call to CleanupThreads(). 50 */ 51 void 52 RegistrarThreadManager::MessageReceived(BMessage* message) 53 { 54 switch (message->what) { 55 case B_REG_MIME_UPDATE_THREAD_FINISHED: 56 { 57 CleanupThreads(); 58 break; 59 } 60 61 default: 62 { 63 BHandler::MessageReceived(message); 64 break; 65 } 66 } 67 } 68 69 // LaunchThread 70 /*! \brief Launches the given thread, passing responsiblity for it onto the 71 RegistrarThreadManager object. 72 73 \param thread Pointer to a newly allocated \c RegistrarThread object. 74 75 If the result of the function is \c B_OK, the \c RegistrarThreadManager object 76 assumes ownership of \a thread; if the result is an error code, it 77 does not. 78 79 \return 80 - \c B_OK: success 81 - \c B_NO_MORE_THREADS: the number of concurrently allowed threads (defined by 82 RegistrarThreadManager::kThreadLimit) has already been reached 83 - \c B_BAD_THREAD_STATE: the thread has already been launched 84 - other error code: failure 85 */ 86 status_t 87 RegistrarThreadManager::LaunchThread(RegistrarThread *thread) 88 { 89 status_t err = thread ? B_OK : B_BAD_VALUE; 90 if (!err) { 91 if (atomic_add(&fThreadCount, 1) >= kThreadLimit) { 92 err = B_NO_MORE_THREADS; 93 atomic_add(&fThreadCount, -1); 94 } 95 } 96 97 if (!err) { 98 fThreads.push_back(thread); 99 err = thread->Run(); 100 if (err) { 101 std::list<RegistrarThread*>::iterator i; 102 for (i = fThreads.begin(); i != fThreads.end();) { 103 if ((*i) == thread) { 104 i = fThreads.erase(i); 105 atomic_add(&fThreadCount, -1); 106 break; 107 } else 108 ++i; 109 } 110 } 111 } 112 if (!err) 113 DBG(OUT("RegistrarThreadManager::LaunchThread(): launched new '%s' thread, " 114 "id %ld\n", thread->Name(), thread->Id())); 115 return err; 116 } 117 118 // CleanupThreads 119 /*! \brief Frees the resources of any threads that are no longer running 120 121 \todo This function should perhaps be triggered periodically by a 122 BMessageRunner once we have our own BMessageRunner implementation. 123 */ 124 status_t 125 RegistrarThreadManager::CleanupThreads() 126 { 127 std::list<RegistrarThread*>::iterator i; 128 for (i = fThreads.begin(); i != fThreads.end(); ) { 129 if (*i) { 130 if ((*i)->IsFinished()) { 131 DBG(OUT("RegistrarThreadManager::CleanupThreads(): Cleaning up thread %ld\n", 132 (*i)->Id())); 133 RemoveThread(i); 134 // adjusts i 135 } else 136 ++i; 137 } else { 138 OUT("WARNING: RegistrarThreadManager::CleanupThreads(): NULL mime_update_thread_shared_data " 139 "pointer found in and removed from RegistrarThreadManager::fThreads list\n"); 140 i = fThreads.erase(i); 141 } 142 } 143 return B_OK; 144 } 145 146 // ShutdownThreads 147 /*! \brief Requests that any running threads quit and frees the resources 148 of any threads that are no longer running. 149 150 \todo This function should be called during system shutdown around 151 the same time as global B_QUIT_REQUESTED messages are sent out. 152 */ 153 status_t 154 RegistrarThreadManager::ShutdownThreads() 155 { 156 std::list<RegistrarThread*>::iterator i; 157 for (i = fThreads.begin(); i != fThreads.end(); ) { 158 if (*i) { 159 if ((*i)->IsFinished()) { 160 DBG(OUT("RegistrarThreadManager::ShutdownThreads(): Cleaning up thread %ld\n", 161 (*i)->Id())); 162 RemoveThread(i); 163 // adjusts i 164 } else { 165 DBG(OUT("RegistrarThreadManager::ShutdownThreads(): Shutting down thread %ld\n", 166 (*i)->Id())); 167 (*i)->AskToExit(); 168 ++i; 169 } 170 } else { 171 OUT("WARNING: RegistrarThreadManager::ShutdownThreads(): NULL mime_update_thread_shared_data " 172 "pointer found in and removed from RegistrarThreadManager::fThreads list\n"); 173 i = fThreads.erase(i); 174 } 175 } 176 177 /*! \todo We may want to iterate back through the list at this point, 178 snooze for a moment if find an unfinished thread, and kill it if 179 it still isn't finished by the time we're done snoozing. 180 */ 181 182 return B_OK; 183 } 184 185 // KillThreads 186 /*! \brief Kills any running threads and frees their resources. 187 188 \todo This function should probably be called during system shutdown 189 just before kernel shutdown begins. 190 */ 191 status_t 192 RegistrarThreadManager::KillThreads() 193 { 194 std::list<RegistrarThread*>::iterator i; 195 for (i = fThreads.begin(); i != fThreads.end(); ) { 196 if (*i) { 197 if (!(*i)->IsFinished()) { 198 DBG(OUT("RegistrarThreadManager::KillThreads(): Killing thread %ld\n", 199 (*i)->Id())); 200 status_t err = kill_thread((*i)->Id()); 201 if (err) 202 OUT("WARNING: RegistrarThreadManager::KillThreads(): kill_thread(%" 203 B_PRId32 ") failed with error code 0x%" B_PRIx32 "\n", 204 (*i)->Id(), err); 205 } 206 DBG(OUT("RegistrarThreadManager::KillThreads(): Cleaning up thread %ld\n", 207 (*i)->Id())); 208 RemoveThread(i); 209 // adjusts i 210 } else { 211 OUT("WARNING: RegistrarThreadManager::KillThreads(): NULL mime_update_thread_shared_data " 212 "pointer found in and removed from RegistrarThreadManager::fThreads list\n"); 213 i = fThreads.erase(i); 214 } 215 } 216 return B_OK; 217 } 218 219 // ThreadCount 220 /*! \brief Returns the number of threads currently under management 221 222 This is not necessarily a count of how many threads are actually running, 223 as threads may remain in the thread list that are finished and waiting 224 to be cleaned up. 225 226 \return The number of threads currently under management 227 */ 228 uint 229 RegistrarThreadManager::ThreadCount() const 230 { 231 return fThreadCount; 232 } 233 234 // RemoveThread 235 /*! \brief Deletes the given thread and removes it from the thread list. 236 */ 237 std::list<RegistrarThread*>::iterator& 238 RegistrarThreadManager::RemoveThread(std::list<RegistrarThread*>::iterator &i) 239 { 240 delete *i; 241 atomic_add(&fThreadCount, -1); 242 return (i = fThreads.erase(i)); 243 } 244 245