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(%ld) failed with " 203 "error code 0x%lx\n", (*i)->Id(), err); 204 } 205 DBG(OUT("RegistrarThreadManager::KillThreads(): Cleaning up thread %ld\n", 206 (*i)->Id())); 207 RemoveThread(i); 208 // adjusts i 209 } else { 210 OUT("WARNING: RegistrarThreadManager::KillThreads(): NULL mime_update_thread_shared_data " 211 "pointer found in and removed from RegistrarThreadManager::fThreads list\n"); 212 i = fThreads.erase(i); 213 } 214 } 215 return B_OK; 216 } 217 218 // ThreadCount 219 /*! \brief Returns the number of threads currently under management 220 221 This is not necessarily a count of how many threads are actually running, 222 as threads may remain in the thread list that are finished and waiting 223 to be cleaned up. 224 225 \return The number of threads currently under management 226 */ 227 uint 228 RegistrarThreadManager::ThreadCount() const 229 { 230 return fThreadCount; 231 } 232 233 // RemoveThread 234 /*! \brief Deletes the given thread and removes it from the thread list. 235 */ 236 std::list<RegistrarThread*>::iterator& 237 RegistrarThreadManager::RemoveThread(std::list<RegistrarThread*>::iterator &i) 238 { 239 delete *i; 240 atomic_add(&fThreadCount, -1); 241 return (i = fThreads.erase(i)); 242 } 243 244