source: box/trunk/lib/common/WaitForEvent.cpp @ 456

Revision 456, 4.1 KB checked in by ben, 6 years ago (diff)

Merge chris/win32/vc2005-compile-fixes @ r455, add infrastructure/msvc to distribution

  • Property svn:eol-style set to native
Line 
1// --------------------------------------------------------------------------
2//
3// File
4//              Name:    WaitForEvent.cpp
5//              Purpose: Generic waiting for events, using an efficient method (platform dependent)
6//              Created: 9/3/04
7//
8// --------------------------------------------------------------------------
9
10#include "Box.h"
11
12#ifdef HAVE_UNISTD_H
13        #include <unistd.h>
14#endif
15
16#include <errno.h>
17#include <string.h>
18
19#include "WaitForEvent.h"
20
21#include "MemLeakFindOn.h"
22
23// --------------------------------------------------------------------------
24//
25// Function
26//              Name:    WaitForEvent::WaitForEvent()
27//              Purpose: Constructor
28//              Created: 9/3/04
29//
30// --------------------------------------------------------------------------
31#ifdef HAVE_KQUEUE
32WaitForEvent::WaitForEvent(int Timeout)
33        : mKQueue(::kqueue()),
34          mpTimeout(0)
35{
36        if(mKQueue == -1)
37        {
38                THROW_EXCEPTION(CommonException, CouldNotCreateKQueue)
39        }
40
41        // Set the choosen timeout
42        SetTimeout(Timeout);
43}
44#else
45WaitForEvent::WaitForEvent(int Timeout)
46        : mTimeout(Timeout),
47          mpPollInfo(0)
48{
49}
50#endif
51
52// --------------------------------------------------------------------------
53//
54// Function
55//              Name:    WaitForEvent::~WaitForEvent()
56//              Purpose: Destructor
57//              Created: 9/3/04
58//
59// --------------------------------------------------------------------------
60WaitForEvent::~WaitForEvent()
61{
62#ifdef HAVE_KQUEUE
63        ::close(mKQueue);
64        mKQueue = -1;
65#else
66        if(mpPollInfo != 0)
67        {
68                ::free(mpPollInfo);
69                mpPollInfo = 0;
70        }
71#endif
72}
73
74
75// --------------------------------------------------------------------------
76//
77// Function
78//              Name:    WaitForEvent::SetTimeout
79//              Purpose: Sets the timeout for future wait calls
80//              Created: 9/3/04
81//
82// --------------------------------------------------------------------------
83void WaitForEvent::SetTimeout(int Timeout)
84{
85#ifdef HAVE_KQUEUE
86        // Generate timeout
87        if(Timeout != TimeoutInfinite)
88        {
89                mTimeout.tv_sec = Timeout / 1000;
90                mTimeout.tv_nsec = (Timeout % 1000) * 1000000;
91        }
92       
93        // Infinite or not?
94        mpTimeout = (Timeout != TimeoutInfinite)?(&mTimeout):(NULL);
95#else
96        mTimeout = Timeout;
97#endif
98}
99
100// --------------------------------------------------------------------------
101//
102// Function
103//              Name:    WaitForEvent::Wait(int)
104//              Purpose: Wait for an event to take place. Returns a pointer to the object
105//                               which has been signalled, or returns 0 for the timeout condition.
106//                               Timeout specified in milliseconds.
107//              Created: 9/3/04
108//
109// --------------------------------------------------------------------------
110void *WaitForEvent::Wait()
111{
112#ifdef HAVE_KQUEUE
113        // Event return structure
114        struct kevent e;
115        ::memset(&e, 0, sizeof(e));
116       
117        switch(::kevent(mKQueue, NULL, 0, &e, 1, mpTimeout))
118        {
119        case 0:
120                // Timeout
121                return 0;
122                break;
123
124        case 1:
125                // Event happened!
126                return e.udata;
127                break;
128               
129        default:
130                // Interrupted system calls aren't an error, just equivalent to a timeout
131                if(errno != EINTR)
132                {
133                        THROW_EXCEPTION(CommonException, KEventErrorWait)
134                }
135                return 0;
136                break;
137        }
138#else
139        // Use poll() instead.
140        // Need to build the structures?
141        if(mpPollInfo == 0)
142        {
143                // Yes...
144                mpPollInfo = (struct pollfd *)::malloc((sizeof(struct pollfd) * mItems.size()) + 4);
145                if(mpPollInfo == 0)
146                {
147                        throw std::bad_alloc();
148                }
149               
150                // Build...
151                for(unsigned int l = 0; l < mItems.size(); ++l)
152                {
153                        mpPollInfo[l].fd = mItems[l].fd;
154                        mpPollInfo[l].events = mItems[l].events;
155                        mpPollInfo[l].revents = 0;
156                }
157        }
158       
159        // Make sure everything is reset (don't really have to do this, but don't trust the OS)
160        for(unsigned int l = 0; l < mItems.size(); ++l)
161        {
162                mpPollInfo[l].revents = 0;
163        }
164       
165        // Poll!
166        switch(::poll(mpPollInfo, mItems.size(), mTimeout))
167        {
168        case -1:
169                // Interrupted system calls aren't an error, just equivalent to a timeout
170                if(errno != EINTR)
171                {
172                        THROW_EXCEPTION(CommonException, KEventErrorWait)
173                }
174                return 0;
175                break;
176        case 0: // timed out
177                return 0;
178                break;
179        default:        // got some thing...
180                // control flows on...
181                break;
182        }
183       
184        // Find the item which was ready
185        for(unsigned int s = 0; s < mItems.size(); ++s)
186        {
187                if(mpPollInfo[s].revents & POLLIN)
188                {
189                        return mItems[s].item;
190                        break;
191                }
192        }
193#endif
194
195        return 0;
196}
197
Note: See TracBrowser for help on using the repository browser.