Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

event.cpp

Go to the documentation of this file.
00001 /*
00002 **  ClanLib SDK
00003 **  Copyright (c) 1997-2005 The ClanLib Team
00004 **
00005 **  This software is provided 'as-is', without any express or implied
00006 **  warranty.  In no event will the authors be held liable for any damages
00007 **  arising from the use of this software.
00008 **
00009 **  Permission is granted to anyone to use this software for any purpose,
00010 **  including commercial applications, and to alter it and redistribute it
00011 **  freely, subject to the following restrictions:
00012 **
00013 **  1. The origin of this software must not be misrepresented; you must not
00014 **     claim that you wrote the original software. If you use this software
00015 **     in a product, an acknowledgment in the product documentation would be
00016 **     appreciated but is not required.
00017 **  2. Altered source versions must be plainly marked as such, and must not be
00018 **     misrepresented as being the original software.
00019 **  3. This notice may not be removed or altered from any source distribution.
00020 **
00021 **  Note: Some of the libraries ClanLib link to may have additional
00022 **  requirements or restrictions.
00023 **
00024 **  File Author(s):
00025 **
00026 **    Magnus Norddahl
00027 */
00028 
00029 #include "precomp.h"
00030 #include "event.h"
00031 #include "exception.h"
00032 #ifndef WIN32
00033 #include <sys/types.h>
00034 #include <sys/socket.h>
00035 #include <sys/time.h>
00036 #include <sys/types.h>
00037 #include <unistd.h>
00038 #endif
00039 
00041 // CL_Event Construction:
00042 
00043 #ifdef WIN32
00044 
00045 CL_Event::CL_Event(bool manual_reset, bool initial_state)
00046 : handle(INVALID_HANDLE_VALUE), type(type_native), socket_handler(0)
00047 {
00048         handle = CreateEvent(
00049                 0,
00050                 manual_reset ? TRUE : FALSE,
00051                 initial_state ? TRUE : FALSE,
00052                 0);
00053         if (handle == INVALID_HANDLE_VALUE)
00054                 throw CL_Exception(TEXT("Unable to create event!"));
00055 }
00056 
00057 CL_Event::CL_Event(CL_SocketEventHandler *socket_handler, EventType type)
00058 : type(type), socket_handler(socket_handler)
00059 {
00060         if (type == type_native)
00061                 throw CL_Exception(TEXT("Invalid type parameter"));
00062 }
00063 
00064 CL_Event::~CL_Event()
00065 {
00066         if (handle != INVALID_HANDLE_VALUE)
00067                 CloseHandle(handle);
00068         handle = INVALID_HANDLE_VALUE;
00069 }
00070 
00071 #else
00072 
00073 CL_Event::CL_Event(bool manual_reset, bool initial_state)
00074 : manual_reset(manual_reset), state(initial_state), type(type_native), socket_handler(0)
00075 {
00076         int result = socketpair(AF_UNIX, SOCK_DGRAM, PF_UNIX, wait_sockets);
00077         if (result == -1)
00078                 throw CL_Exception(TEXT("Could not create event waiting socket pair!"));
00079 }
00080 
00081 CL_Event::CL_Event(CL_SocketEventHandler *socket_handler, EventType type)
00082 : manual_reset(true), state(false), type(type), socket_handler(socket_handler)
00083 {
00084         if (type == type_native)
00085                 throw CL_Exception(TEXT("Invalid type parameter"));
00086 }
00087 
00088 CL_Event::~CL_Event()
00089 {
00090         if (type == type_native)
00091         {
00092                 close(wait_sockets[0]);
00093                 close(wait_sockets[1]);
00094         }
00095 }
00096 
00097 #endif
00098 
00099 
00101 // CL_Event Attributes:
00102 
00104 // CL_Event Operations:
00105 
00106 bool CL_Event::wait(int timeout) const
00107 {
00108 #ifdef WIN32
00109         switch (type)
00110         {
00111         case type_native:
00112                 {
00113                         DWORD result = WaitForSingleObject(handle, (timeout == -1) ? INFINITE : timeout);
00114                         return (result != WAIT_TIMEOUT);
00115                 }
00116 
00117         case type_socket_read:
00118         case type_socket_write:
00119         case type_socket_exception:
00120                 {
00121                         timeval tv;
00122                         tv.tv_sec = timeout / 1000;
00123                         tv.tv_usec = (timeout % 1000) * 1000;
00124 
00125                         fd_set fds;
00126                         FD_ZERO(&fds);
00127                         FD_SET(socket_handler->socket_handle, &fds);
00128                 
00129                         int result = select((int) socket_handler->socket_handle+1,
00130                                 (type == type_socket_read) ? &fds : 0,
00131                                 (type == type_socket_write) ? &fds : 0,
00132                                 (type == type_socket_exception) ? &fds : 0,
00133                                 (timeout == -1) ? 0 : &tv);
00134                         if (result == -1) // Error occoured
00135                         {
00136                                 throw CL_Exception(TEXT("Event wait failed!"));
00137                         }
00138                         else if (result == 0) // Timed out
00139                         {
00140                                 return false;
00141                         }
00142                         else // Got a message
00143                         {
00144                                 return true;
00145                         }
00146                 }
00147                 return false;
00148 
00149         default:
00150                 throw CL_Exception(TEXT("Unknown event type"));
00151                 return false;
00152         }
00153 #else
00154         // Placing the timeval struct here allows linux systems to more
00155         // correctly resume a select if it was awaken by a manual reset
00156         // event. On non-linux unixes (those that do not update timeval),
00157         // the timeout precision will be more inaccurate for manual reset
00158         // events with multiple listeners.
00159         //   -- mbn 4 nov 2004
00160         timeval tv;
00161         tv.tv_sec = timeout / 1000;
00162         tv.tv_usec = (timeout % 1000) * 1000;
00163 
00164         while (true)
00165         {
00166                 fd_set fds;
00167                 FD_ZERO(&fds);
00168                 if (type == type_native)
00169                         FD_SET(wait_sockets[1], &fds);
00170                 else
00171                         FD_SET(socket_handler->socket_handle, &fds);
00172                 
00173                 int result = select(
00174                         (type == type_native) ? wait_sockets[1]+1 : socket_handler->socket_handle+1,
00175                         (type == type_native || type == type_socket_read) ? &fds : 0,
00176                         (type == type_socket_write) ? &fds : 0,
00177                         (type == type_socket_exception) ? &fds : 0,
00178                         (timeout == -1) ? 0 : &tv);
00179                 if (result == -1) // Error occoured
00180                 {
00181                         throw CL_Exception(TEXT("Event wait failed!"));
00182                 }
00183                 else if (result == 0) // Timed out
00184                 {
00185                         return false;
00186                 }
00187                 else // Got a message
00188                 {
00189                         if (!manual_reset || type != type_native)
00190                         {
00191                                 return true;
00192                         }
00193                         else
00194                         {
00195                                 // For automatic reset, check if we are first
00196                                 // thread:
00197                                 CL_MutexSection mutex_lock(&mutex);
00198                                 if (state == true)
00199                                 {
00200                                         char msg = 0;
00201                                         recv(wait_sockets[1], &msg, sizeof(char), 0);
00202                                         state = false;
00203                                         return true;
00204                                 }
00205 
00206                                 // Someone beat us to it, go back and wait.
00207                         }
00208                 }
00209         }
00210 
00211         return false;
00212 #endif
00213 }
00214 
00215 int CL_Event::wait(int count, CL_Event const * const * events, int timeout, bool wait_all)
00216 {
00217 #ifdef WIN32
00218         if (count == 0)
00219         {
00220                 WaitForMultipleObjects(0, 0, FALSE, (timeout == -1) ? INFINITE : timeout);
00221                 return -1;
00222         }
00223 
00224         std::vector<HANDLE> handles;
00225         for (int i=0; i<count; i++)
00226                 handles.push_back(events[i]->handle);
00227                 
00228         DWORD result = WaitForMultipleObjects(
00229                 count,
00230                 &handles[0],
00231                 wait_all ? TRUE : FALSE,
00232                 (timeout == -1) ? INFINITE : timeout);
00233         
00234         if (result >= WAIT_OBJECT_0 && result < WAIT_OBJECT_0 + count)
00235                 return result - WAIT_OBJECT_0;
00236         else if (result >= WAIT_ABANDONED_0 && result < WAIT_ABANDONED_0 + count)
00237                 return result - WAIT_ABANDONED_0;
00238         else
00239                 return -1;
00240 #else
00241         if (wait_all == true)
00242                 throw CL_Exception(TEXT("wait_all not implemented yet for unix target"));
00243 
00244         // Placing the timeval struct here allows linux systems to more
00245         // correctly resume a select if it was awaken by a manual reset
00246         // event. On non-linux unixes (those that do not update timeval),
00247         // the timeout precision will be more inaccurate for manual reset
00248         // events with multiple listeners.
00249         //   -- mbn 4 nov 2004
00250         timeval tv;
00251         tv.tv_sec = timeout / 1000;
00252         tv.tv_usec = (timeout % 1000) * 1000;
00253 
00254         while (true)
00255         {       
00256                 bool reads = false;
00257                 bool writes = false;
00258                 bool exceptions = false;
00259                 int highest_fd = -1;
00260                 fd_set rfds, wfds, efds;
00261                 FD_ZERO(&rfds);
00262                 FD_ZERO(&wfds);
00263                 FD_ZERO(&efds);
00264                 for (int i=0; i<count; i++)
00265                 {
00266                         switch (events[i]->type)
00267                         {
00268                         case type_native:
00269                                 FD_SET(events[i]->wait_sockets[1], &rfds);
00270                                 if (events[i]->wait_sockets[1] > highest_fd)
00271                                         highest_fd = events[i]->wait_sockets[1];
00272                                 reads = true;
00273                                 break;
00274                         case type_socket_read:
00275                                 FD_SET(events[i]->socket_handler->socket_handle, &rfds);
00276                                 if (events[i]->socket_handler->socket_handle > highest_fd)
00277                                         highest_fd = events[i]->socket_handler->socket_handle;
00278                                 reads = true;
00279                                 break;
00280                         case type_socket_write:
00281                                 FD_SET(events[i]->socket_handler->socket_handle, &wfds);
00282                                 if (events[i]->socket_handler->socket_handle > highest_fd)
00283                                         highest_fd = events[i]->socket_handler->socket_handle;
00284                                 writes = true;
00285                                 break;
00286                         case type_socket_exception:
00287                                 FD_SET(events[i]->socket_handler->socket_handle, &efds);
00288                                 if (events[i]->socket_handler->socket_handle > highest_fd)
00289                                         highest_fd = events[i]->socket_handler->socket_handle;
00290                                 exceptions = true;
00291                                 break;
00292                         }
00293                 }
00294 
00295                 int result = select(
00296                         highest_fd+1,
00297                         reads ? &rfds : 0,
00298                         writes ? &wfds : 0,
00299                         exceptions ? &efds : 0,
00300                         (timeout == -1) ? 0 : &tv);
00301                 if (result == -1) // Error occoured
00302                 {
00303                         throw CL_Exception(TEXT("Event wait failed!"));
00304                 }
00305                 else if (result == 0) // Timed out
00306                 {
00307                         return -1;
00308                 }
00309                 else // Got a message
00310                 {
00311                         // find the flagged sockets
00312                         for (int i=0; i<count; i++)
00313                         {
00314                                 switch (events[i]->type)
00315                                 {
00316                                 case type_native:
00317                                         if (FD_ISSET(events[i]->wait_sockets[1], &rfds))
00318                                         {
00319                                                 if (!events[i]->manual_reset)
00320                                                 {
00321                                                         return i;
00322                                                 }
00323                                                 else
00324                                                 {
00325                                                         // For automatic reset, check if we are first
00326                                                         // thread:
00327                                                         CL_MutexSection mutex_lock(&events[i]->mutex);
00328                                                         if (events[i]->state == true)
00329                                                         {
00330                                                                 char msg = 0;
00331                                                                 recv(events[i]->wait_sockets[1], &msg, sizeof(char), 0);
00332                                                                 events[i]->state = false;
00333                                                                 return i;
00334                                                         }
00335 
00336                                                         // Someone beat us to it, go back and wait.
00337                                                 }
00338                                         }
00339                                         break;
00340                                 case type_socket_read:
00341                                         if (FD_ISSET(events[i]->socket_handler->socket_handle, &rfds))
00342                                                 return i;
00343                                         break;
00344                                 case type_socket_write:
00345                                         if (FD_ISSET(events[i]->socket_handler->socket_handle, &wfds))
00346                                                 return i;
00347                                         break;
00348                                 case type_socket_exception:
00349                                         if (FD_ISSET(events[i]->socket_handler->socket_handle, &efds))
00350                                                 return i;
00351                                         break;
00352                                 }
00353                         }
00354                 }
00355         }
00356         
00357         return -1;
00358 #endif
00359 }
00360 
00361 int CL_Event::wait(const std::vector<CL_Event *> &events, int timeout, bool wait_all)
00362 {
00363         if (events.size() > 0)
00364                 return wait((int) events.size(), &events[0], timeout, wait_all);
00365         else
00366                 return wait(0, 0, timeout, wait_all);
00367 }
00368 
00369 void CL_Event::set()
00370 {
00371         if (type != type_native)
00372                 throw CL_Exception(TEXT("Changing state on socket events unsupported"));
00373 
00374 #ifdef WIN32
00375         BOOL result = SetEvent(handle);
00376         if (result == FALSE)
00377                 throw CL_Exception(TEXT("Unable to set event to signalled state!"));
00378 #else
00379         CL_MutexSection mutex_lock(&mutex);
00380         if (state == false)
00381         {
00382                 state = true;
00383                 char msg = 1;
00384                 send(wait_sockets[0], &msg, sizeof(char), 0);
00385         }
00386 #endif
00387 }
00388 
00389 void CL_Event::reset()
00390 {
00391         if (type != type_native)
00392                 throw CL_Exception(TEXT("Changing state on socket events unsupported"));
00393 
00394 #ifdef WIN32
00395         BOOL result = ResetEvent(handle);
00396         if (result == FALSE)
00397                 throw CL_Exception(TEXT("Unable to reset event!"));
00398 #else
00399         CL_MutexSection mutex_lock(&mutex);
00400         if (state == true)
00401         {
00402                 char msg = 0;
00403                 recv(wait_sockets[1], &msg, sizeof(char), 0);
00404                 state = false;
00405         }
00406 #endif
00407 }
00408 
00410 // CL_Event Implementation:
00411 
00412 CL_Event::CL_Event(const CL_Event &copy)
00413 {
00414         throw CL_Exception(TEXT("Event class copy construction not supported"));
00415 }
00416         
00417 CL_Event &CL_Event::operator =(const CL_Event &copy)
00418 {
00419         throw CL_Exception(TEXT("Event class copy construction not supported"));
00420         return *this;
00421 }

Generated on Sat Feb 19 22:51:16 2005 for npcore by  doxygen 1.4.1