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