1/* 2 * Copyright 2009 Oliver Ruiz Dorantes, oliver.ruiz.dorantes_at_gmail.com 3 * All rights reserved. Distributed under the terms of the MIT License. 4 */ 5#ifndef PORTLISTENER_H_ 6#define PORTLISTENER_H_ 7 8#include <OS.h> 9 10template < 11 typename TYPE, 12 ssize_t MAX_MESSAGE_SIZE = 256, 13 size_t MAX_MESSAGE_DEEP = 16, 14 uint32 PRIORITY = B_URGENT_DISPLAY_PRIORITY> 15class PortListener { 16public: 17 typedef status_t (*port_listener_func)(TYPE*, int32, size_t); 18 19 PortListener(const char* name, port_listener_func handler) 20 { 21 fInformation.func = handler; 22 fInformation.port = &fPort; 23 24 fPortName = strdup(name); 25 26 fThreadName = (char*)malloc(strlen(name) + strlen(" thread") + 1); 27 fThreadName = strcpy(fThreadName, fPortName); 28 fThreadName = strcat(fThreadName, " thread"); 29 30 InitCheck(); 31 } 32 33 34 ~PortListener() 35 { 36 status_t status; 37 38 close_port(fPort); 39 // Closing the port should provoke the thread to finish 40 wait_for_thread(fThread, &status); 41 42 free(fThreadName); 43 free(fPortName); 44 } 45 46 47 status_t Trigger(int32 code) 48 { 49 return write_port(fPort, code, NULL, 0); 50 } 51 52 53 status_t Trigger(int32 code, TYPE* buffer, size_t size) 54 { 55 if (buffer == NULL) 56 return B_ERROR; 57 58 return write_port(fPort, code, buffer, size); 59 } 60 61 62 status_t InitCheck() 63 { 64 // Create Port 65 fPort = find_port(fPortName); 66 if (fPort == B_NAME_NOT_FOUND) { 67 fPort = create_port(MAX_MESSAGE_DEEP, fPortName); 68 } 69 70 if (fPort < B_OK) 71 return fPort; 72 73 #ifdef KERNEL_LAND 74 // if this is the case you better stay with kernel 75 set_port_owner(fPort, B_SYSTEM_TEAM); 76 #endif 77 78 // Create Thread 79 fThread = find_thread(fThreadName); 80 if (fThread < B_OK) { 81#ifdef KERNEL_LAND 82 fThread = spawn_kernel_thread((thread_func)&PortListener<TYPE, 83 MAX_MESSAGE_SIZE, MAX_MESSAGE_DEEP, PRIORITY>::threadFunction, 84 fThreadName, PRIORITY, &fInformation); 85#else 86 fThread = spawn_thread((thread_func)&PortListener<TYPE, 87 MAX_MESSAGE_SIZE, MAX_MESSAGE_DEEP, PRIORITY>::threadFunction, 88 fThreadName, PRIORITY, &fInformation); 89#endif 90 } 91 92 if (fThread < B_OK) 93 return fThread; 94 95 return B_OK; 96 } 97 98 99 status_t Launch() 100 { 101 status_t check = InitCheck(); 102 103 if (check < B_OK) 104 return check; 105 106 return resume_thread(fThread); 107 } 108 109 110 status_t Stop() 111 { 112 status_t status; 113 114 close_port(fPort); 115 // Closing the port should provoke the thread to finish 116 wait_for_thread(fThread, &status); 117 118 return status; 119 } 120 121 122private: 123 124 struct PortListenerInfo { 125 port_id* port; 126 port_listener_func func; 127 } fInformation; 128 129 port_id fPort; 130 thread_id fThread; 131 char* fThreadName; 132 char* fPortName; 133 134 static int32 threadFunction(void* data) 135 { 136 ssize_t ssizePort; 137 ssize_t ssizeRead; 138 status_t status = B_OK; 139 int32 code; 140 141 port_id* port = ((struct PortListenerInfo*)data)->port; 142 port_listener_func handler = ((struct PortListenerInfo*)data)->func; 143 144 145 TYPE* buffer = (TYPE*)malloc(MAX_MESSAGE_SIZE); 146 147 while ((ssizePort = port_buffer_size(*port)) != B_BAD_PORT_ID) { 148 149 if (ssizePort <= 0) { 150 snooze(500 * 1000); 151 continue; 152 } 153 154 if (ssizePort > MAX_MESSAGE_SIZE) { 155 snooze(500 * 1000); 156 continue; 157 } 158 159 ssizeRead = read_port(*port, &code, (void*)buffer, ssizePort); 160 161 if (ssizeRead != ssizePort) 162 continue; 163 164 status = handler(buffer, code, ssizePort); 165 166 if (status != B_OK) 167 break; 168 169 } 170 171 #ifdef DEBUG_PORTLISTENER 172 #ifdef KERNEL_LAND 173 dprintf("Error in PortListener handler=%s port=%s\n", strerror(status), 174 strerror(ssizePort)); 175 #else 176 printf("Error in PortListener handler=%s port=%s\n", strerror(status), 177 strerror(ssizePort)); 178 #endif 179 #endif 180 181 free(buffer); 182 183 if (ssizePort == B_BAD_PORT_ID) // the port disappeared 184 return ssizePort; 185 186 return status; 187 } 188 189}; // PortListener 190 191#endif // PORTLISTENER_H_ 192