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