]> git.vomp.tv Git - vompclient.git/blob - eventdispatcher.cc
Some fixes on cancellation points
[vompclient.git] / eventdispatcher.cc
1 /*
2     Copyright 2007 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20
21 #include "eventdispatcher.h"
22 #include <stdlib.h>
23
24
25 EventDispatcher::EventDispatcher()
26 {
27 #ifndef WIN32
28   pthread_mutex_init(&mutex, NULL);
29 #else
30   mutex = CreateMutex(NULL, FALSE, NULL);
31 #endif
32 }
33
34 void EventDispatcher::edRegister(EDReceiver* edr)
35 {
36   edLock();
37   receivers.push_back(edr);
38   edUnlock();
39 }  
40
41 bool EventDispatcher::edFindAndCall(void* userTag)
42 {
43   edLock();
44   
45   EDReceiver* edr = NULL;
46   EDRL::iterator i;
47   for(i = receivers.begin(); i != receivers.end(); i++)
48   {
49     if (ed_cb_find(*i, userTag))
50     {
51       edr = *i;
52       break; // found (by asking the EventDispatcher implementor to check if userTag is for *i
53     }
54   }
55   
56   if ((i == receivers.end()) || edr->callinprogress || edr->nomorecalls)
57   {
58     edUnlock();
59     return false;
60   }
61   
62   edr->callinprogress = true;
63   edUnlock();  
64   bool edrType = edr->call(userTag);
65   edLock();
66   edr->callinprogress = false;
67
68   if (edrType == false) // it's a multicall
69   {
70     if (edr->nomorecalls) // External has called unRegister - probably the receiver
71     {
72       // wake up the thread waiting in unregister
73       #ifndef WIN32
74       pthread_cond_signal(&edr->cond);
75       #else
76       SetEvent(edr->cond);
77       #endif
78     }
79   }
80   else // It's a single call. The receiver should be removed from the list. There will be a thread to wake up
81   {
82     for(i = receivers.begin(); i != receivers.end(); i++)
83     {
84       if (*i == edr)
85       {
86         receivers.erase(i);
87         break;
88       }
89     }
90     #ifndef WIN32
91     if (i == receivers.end()) abort(); // should never happen
92     // but it can happen under windows ... how??
93     #endif
94     
95     #ifndef WIN32
96     pthread_cond_signal(&edr->cond);
97     #else
98     SetEvent(edr->cond);
99     #endif
100   }
101   
102   edUnlock();
103   return true;
104 }
105
106 void EventDispatcher::edUnregister(EDReceiver* edr)
107 {
108   edLock();
109
110   EDRL::iterator i;
111   for(i = receivers.begin(); i != receivers.end(); i++)
112   {
113     if (*i == edr) break; // found
114   }
115
116   // Not in the list. Already unregistered? Perhaps vdr::connectionDied already removed this streamclient
117   // FIXME, this should probably be done another way. A call to edUnregister with an object that may or may not be in the list? Not good.
118   if (i == receivers.end())
119   {
120     edUnlock();
121     return;
122   }
123
124   if (!edr->callinprogress)
125   {
126     receivers.erase(i);
127     edUnlock();
128     return;
129   }
130
131   edr->nomorecalls = true;
132   
133   // edUnlock, wait for callinprogres=false (cond to be signalled), lock  
134 #ifndef WIN32
135   pthread_cond_wait(&edr->cond, &mutex);
136 #else
137   ReleaseMutex(mutex);
138   WaitForSingleObject(edr->cond,INFINITE);
139   WaitForSingleObject(mutex, INFINITE);
140   ResetEvent(edr->cond);
141
142 #endif
143
144   for(i = receivers.begin(); i != receivers.end(); i++)
145   {
146     if (*i == edr) break; // found
147   }
148
149   if (i == receivers.end()) abort(); // should never happen
150
151   receivers.erase(i);
152   edUnlock();
153 }
154
155 // ---------------------------------------
156
157 void EventDispatcher::edLock()
158 {
159 #ifndef WIN32
160   pthread_mutex_lock(&mutex);
161 #else
162   WaitForSingleObject(mutex, INFINITE);
163 #endif
164 }
165
166 void EventDispatcher::edUnlock()
167 {
168 #ifndef WIN32
169   pthread_mutex_unlock(&mutex);
170 #else
171   ReleaseMutex(mutex);
172 #endif
173 }
174
175 // ---------------------------------------
176
177 void EventDispatcher::edSleepThisReceiver(EDReceiver* edr)
178 {
179   // For blocking version, not callback version. Call with edLock locked
180   
181 #ifndef WIN32
182   pthread_cond_wait(&edr->cond, &mutex);
183 #else
184    ResetEvent(edr->cond);
185    ReleaseMutex(mutex);
186    WaitForSingleObject(edr->cond,INFINITE);
187    ResetEvent(edr->cond);
188    WaitForSingleObject(mutex, INFINITE);
189 #endif
190 }
191
192 // -------------- EDReceiver implementation
193
194 EDReceiver::EDReceiver()
195 {
196   nomorecalls = false;
197   callinprogress = false;
198 #ifndef WIN32
199   pthread_cond_init(&cond, NULL);
200 #else
201    cond = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL);
202 #endif
203 }
204
205 EDReceiver::~EDReceiver()
206 {
207 #ifdef WIN32
208   if (cond!=NULL) CloseHandle(cond);
209 #else
210   pthread_cond_destroy(&cond);
211 #endif
212 }