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