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 19MessageLooper::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 30MessageLooper::~MessageLooper() 31{ 32 free((void*)fName); 33} 34 35 36status_t 37MessageLooper::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 64void 65MessageLooper::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*/ 91status_t 92MessageLooper::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*/ 101status_t 102MessageLooper::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 116void 117MessageLooper::_PrepareQuit() 118{ 119 // to be implemented by subclasses 120} 121 122 123void 124MessageLooper::_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 133void 134MessageLooper::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) 135{ 136} 137 138 139void 140MessageLooper::_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*/ 172int32 173MessageLooper::_message_thread(void* _looper) 174{ 175 MessageLooper* looper = (MessageLooper*)_looper; 176 177 looper->_MessageLooper(); 178 return 0; 179} 180 181