1 /* 2 * Copyright 2005-2007, Haiku. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler, axeld@pinc-software.de 7 */ 8 9 10 #include "MessageLooper.h" 11 12 #include <Autolock.h> 13 #include <stdio.h> 14 #include <string.h> 15 16 17 MessageLooper::MessageLooper(const char* name) 18 : BLocker(name), 19 fThread(-1), 20 fQuitting(false), 21 fDeathSemaphore(-1) 22 { 23 } 24 25 26 MessageLooper::~MessageLooper() 27 { 28 } 29 30 31 bool 32 MessageLooper::Run() 33 { 34 BAutolock locker(this); 35 36 fQuitting = false; 37 38 char name[B_OS_NAME_LENGTH]; 39 _GetLooperName(name, sizeof(name)); 40 41 // Spawn our message-monitoring thread 42 fThread = spawn_thread(_message_thread, name, B_DISPLAY_PRIORITY, this); 43 if (fThread < B_OK) { 44 fQuitting = true; 45 return false; 46 } 47 48 if (resume_thread(fThread) != B_OK) { 49 fQuitting = true; 50 kill_thread(fThread); 51 fThread = -1; 52 return false; 53 } 54 55 return true; 56 } 57 58 59 void 60 MessageLooper::Quit() 61 { 62 fQuitting = true; 63 _PrepareQuit(); 64 65 if (fThread < B_OK) { 66 // thread has not been started yet 67 delete this; 68 return; 69 } 70 71 if (fThread == find_thread(NULL)) { 72 // called from our message looper 73 delete this; 74 exit_thread(0); 75 } else { 76 // called from a different thread 77 PostMessage(kMsgQuitLooper); 78 } 79 } 80 81 82 /*! 83 \brief Send a message to the looper without any attachments 84 \param code ID code of the message to post 85 */ 86 status_t 87 MessageLooper::PostMessage(int32 code, bigtime_t timeout) 88 { 89 BPrivate::LinkSender link(MessagePort()); 90 link.StartMessage(code); 91 return link.Flush(timeout); 92 } 93 94 95 /*static*/ 96 status_t 97 MessageLooper::WaitForQuit(sem_id semaphore, bigtime_t timeout) 98 { 99 status_t status; 100 do { 101 status = acquire_sem_etc(semaphore, 1, B_RELATIVE_TIMEOUT, timeout); 102 } while (status == B_INTERRUPTED); 103 104 if (status == B_TIMED_OUT) 105 return status; 106 107 return B_OK; 108 } 109 110 111 void 112 MessageLooper::_PrepareQuit() 113 { 114 // to be implemented by subclasses 115 } 116 117 118 void 119 MessageLooper::_GetLooperName(char* name, size_t length) 120 { 121 sem_id semaphore = Sem(); 122 sem_info info; 123 if (get_sem_info(semaphore, &info) == B_OK) 124 strlcpy(name, info.name, length); 125 else 126 strlcpy(name, "unnamed looper", length); 127 } 128 129 130 void 131 MessageLooper::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) 132 { 133 } 134 135 136 void 137 MessageLooper::_MessageLooper() 138 { 139 BPrivate::LinkReceiver& receiver = fLink.Receiver(); 140 141 while (true) { 142 int32 code; 143 status_t status = receiver.GetNextMessage(code); 144 if (status < B_OK) { 145 // that shouldn't happen, it's our port 146 char name[256]; 147 _GetLooperName(name, 256); 148 printf("MessageLooper \"%s\": Someone deleted our message port %ld, %s!\n", 149 name, receiver.Port(), strerror(status)); 150 break; 151 } 152 153 Lock(); 154 155 if (code == kMsgQuitLooper) { 156 Quit(); 157 } else 158 _DispatchMessage(code, receiver); 159 160 Unlock(); 161 } 162 } 163 164 165 /*! 166 \brief Message-dispatching loop starter 167 */ 168 /*static*/ 169 int32 170 MessageLooper::_message_thread(void* _looper) 171 { 172 MessageLooper* looper = (MessageLooper*)_looper; 173 174 looper->_MessageLooper(); 175 return 0; 176 } 177 178