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 strcpy(name, "unnamed looper"); 122 } 123 124 125 void 126 MessageLooper::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) 127 { 128 } 129 130 131 void 132 MessageLooper::_MessageLooper() 133 { 134 BPrivate::LinkReceiver& receiver = fLink.Receiver(); 135 136 while (true) { 137 int32 code; 138 status_t status = receiver.GetNextMessage(code); 139 if (status < B_OK) { 140 // that shouldn't happen, it's our port 141 printf("Someone deleted our message port!\n"); 142 break; 143 } 144 145 Lock(); 146 147 if (code == kMsgQuitLooper) { 148 Quit(); 149 } else 150 _DispatchMessage(code, receiver); 151 152 Unlock(); 153 } 154 } 155 156 157 /*! 158 \brief Message-dispatching loop starter 159 */ 160 /*static*/ 161 int32 162 MessageLooper::_message_thread(void* _looper) 163 { 164 MessageLooper* looper = (MessageLooper*)_looper; 165 166 looper->_MessageLooper(); 167 return 0; 168 } 169 170