]> git.vomp.tv Git - vompclient.git/blob - eventdispatcher.cc
Fix removeAll in BoxStack
[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
23 EventDispatcher::EventDispatcher()
24 {
25 #ifndef WIN32
26   pthread_mutex_init(&mutex, NULL);
27 #else
28   mutex = CreateMutex(NULL, FALSE, NULL);
29 #endif
30 }
31
32 void EventDispatcher::edRegister(EDReceiver* edr)
33 {
34   edLock();
35   receivers.push_back(edr);
36   edUnlock();
37 }  
38
39 bool EventDispatcher::edFindAndCall(void* userTag)
40 {
41   edLock();
42   
43   EDReceiver* edr = NULL;
44   EDRL::iterator i;
45   for(i = receivers.begin(); i != receivers.end(); i++)
46   {
47     if (ed_cb_find(*i, userTag))
48     {
49       edr = *i;
50       break; // found (by asking the EventDispatcher implementor to check if userTag is for *i
51     }
52   }
53   
54   if ((i == receivers.end()) || edr->callinprogress || edr->nomorecalls)
55   {
56     edUnlock();
57     return false;
58   }
59   
60   edr->callinprogress = true;
61   edUnlock();  
62   bool edrType = edr->call(userTag);
63   edLock();
64   edr->callinprogress = false;
65
66   if (edrType == false) // it's a multicall
67   {
68     if (edr->nomorecalls) // External has called unRegister - probably the receiver
69     {
70       // wake up the thread waiting in unregister
71       #ifndef WIN32
72       pthread_cond_signal(&edr->cond);
73       #else
74       SetEvent(edr->cond);
75       #endif
76     }
77   }
78   else // It's a single call. The receiver should be removed from the list. There will be a thread to wake up
79   {
80     for(i = receivers.begin(); i != receivers.end(); i++)
81     {
82       if (*i == edr)
83       {
84         receivers.erase(i);
85         break;
86       }
87     }
88     #ifndef WIN32
89     if (i == receivers.end()) abort(); // should never happen
90     // but it can happen under windows ... how??
91     #endif
92     
93     #ifndef WIN32
94     pthread_cond_signal(&edr->cond);
95     #else
96     SetEvent(edr->cond);
97     #endif
98   }
99   
100   edUnlock();
101   return true;
102 }
103
104 void EventDispatcher::edUnregister(EDReceiver* edr)
105 {
106   edLock();
107
108   EDRL::iterator i;
109   for(i = receivers.begin(); i != receivers.end(); i++)
110   {
111     if (*i == edr) break; // found
112   }
113
114   // Not in the list. Already unregistered? Perhaps vdr::connectionDied already removed this streamclient
115   // 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.
116   if (i == receivers.end())
117   {
118     edUnlock();
119     return;
120   }
121
122   if (!edr->callinprogress)
123   {
124     receivers.erase(i);
125     edUnlock();
126     return;
127   }
128
129   edr->nomorecalls = true;
130   
131   // edUnlock, wait for callinprogres=false (cond to be signalled), lock  
132 #ifndef WIN32
133   pthread_cond_wait(&edr->cond, &mutex);
134 #else
135   ReleaseMutex(mutex);
136   WaitForSingleObject(edr->cond,INFINITE);
137   WaitForSingleObject(mutex, INFINITE);
138   ResetEvent(edr->cond);
139
140 #endif
141
142   for(i = receivers.begin(); i != receivers.end(); i++)
143   {
144     if (*i == edr) break; // found
145   }
146
147   if (i == receivers.end()) abort(); // should never happen
148
149   receivers.erase(i);
150   edUnlock();
151 }
152
153 // ---------------------------------------
154
155 void EventDispatcher::edLock()
156 {
157 #ifndef WIN32
158   pthread_mutex_lock(&mutex);
159 #else
160   WaitForSingleObject(mutex, INFINITE);
161 #endif
162 }
163
164 void EventDispatcher::edUnlock()
165 {
166 #ifndef WIN32
167   pthread_mutex_unlock(&mutex);
168 #else
169   ReleaseMutex(mutex);
170 #endif
171 }
172
173 // ---------------------------------------
174
175 void EventDispatcher::edSleepThisReceiver(EDReceiver* edr)
176 {
177   // For blocking version, not callback version. Call with edLock locked
178   
179 #ifndef WIN32
180   pthread_cond_init(&edr->cond, NULL);
181   pthread_cond_wait(&edr->cond, &mutex);
182 #else
183    edr->cond = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL);
184    ReleaseMutex(mutex);
185    WaitForSingleObject(edr->cond,INFINITE);
186    ResetEvent(edr->cond);
187    WaitForSingleObject(mutex, INFINITE);
188 #endif
189 }
190
191 // -------------- EDReceiver implementation
192
193 EDReceiver::EDReceiver()
194 {
195   nomorecalls = false;
196   callinprogress = false;
197 #ifdef WIN32
198   cond=NULL;
199 #endif
200 }
201
202 EDReceiver::~EDReceiver()
203 {
204 #ifdef WIN32
205   if (cond!=NULL) CloseHandle(cond);
206 #endif
207 }