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