]> git.vomp.tv Git - vompclient.git/blob - eventdispatcher.cc
Fix text corruption on channel list when returning from live TV
[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 r_deregisterEDR = false;
65   bool r_wakeThread = false;
66   bool r_deleteEDR = false;
67   edr->call(userTag, r_deregisterEDR, r_wakeThread, r_deleteEDR);
68   edLock();
69   edr->callinprogress = false;
70
71
72   // if it's a stream packet (r_deregisterEDR == false)
73   // and edr->nomorecalls == true
74   // then something has called unregister for this EDR while we were out on the call
75   // set r_wakeThread to ensure that we signal the edr->cond to wake up that thread in edUnregister below
76   if ((r_deregisterEDR == false) && (edr->nomorecalls))
77   {
78     r_wakeThread = true;
79   }
80
81   if (r_deregisterEDR)
82   {
83     for(i = receivers.begin(); i != receivers.end(); i++)
84     {
85       if (*i == edr)
86       {
87         receivers.erase(i);
88         break;
89       }
90     }
91     #ifndef WIN32
92     if (i == receivers.end()) abort(); // should never happen
93     // but it can happen under windows ... how??
94     #endif
95   }
96
97   if (r_wakeThread)
98   {
99     #ifndef WIN32
100     pthread_cond_signal(&edr->cond);
101     #else
102     SetEvent(edr->cond);
103     #endif
104   }
105
106   if (r_deleteEDR)
107   {
108     delete edr;
109   }
110   
111   edUnlock();
112   return true;
113 }
114
115 void EventDispatcher::edUnregister(EDReceiver* edr)
116 {
117   edLock();
118
119   EDRL::iterator i;
120   for(i = receivers.begin(); i != receivers.end(); i++)
121   {
122     if (*i == edr) break; // found
123   }
124
125   // Not in the list. Already unregistered? Perhaps vdr::connectionDied already removed this streamclient
126   // 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.
127   if (i == receivers.end())
128   {
129     edUnlock();
130     return;
131   }
132
133   if (!edr->callinprogress)
134   {
135     receivers.erase(i);
136     edUnlock();
137     return;
138   }
139
140   edr->nomorecalls = true;
141   
142   // edUnlock, wait for callinprogres=false (cond to be signalled), lock  
143 #ifndef WIN32
144   pthread_cond_wait(&edr->cond, &mutex);
145 #else
146   ReleaseMutex(mutex);
147   WaitForSingleObject(edr->cond,INFINITE);
148   WaitForSingleObject(mutex, INFINITE);
149   ResetEvent(edr->cond);
150
151 #endif
152
153   for(i = receivers.begin(); i != receivers.end(); i++)
154   {
155     if (*i == edr) break; // found
156   }
157
158   if (i == receivers.end()) abort(); // should never happen
159
160   receivers.erase(i);
161   edUnlock();
162 }
163
164 // ---------------------------------------
165
166 void EventDispatcher::edLock()
167 {
168 #ifndef WIN32
169   pthread_mutex_lock(&mutex);
170 #else
171   WaitForSingleObject(mutex, INFINITE);
172 #endif
173 }
174
175 void EventDispatcher::edUnlock()
176 {
177 #ifndef WIN32
178   pthread_mutex_unlock(&mutex);
179 #else
180   ReleaseMutex(mutex);
181 #endif
182 }
183
184 // ---------------------------------------
185
186 void EventDispatcher::edSleepThisReceiver(EDReceiver* edr)
187 {
188   // For blocking version, not callback version. Call with edLock locked
189   
190 #ifndef WIN32
191   pthread_cond_wait(&edr->cond, &mutex);
192 #else
193    ResetEvent(edr->cond);
194    ReleaseMutex(mutex);
195    WaitForSingleObject(edr->cond,INFINITE);
196    ResetEvent(edr->cond);
197    WaitForSingleObject(mutex, INFINITE);
198 #endif
199 }
200
201 // -------------- EDReceiver implementation
202
203 EDReceiver::EDReceiver()
204 {
205   nomorecalls = false;
206   callinprogress = false;
207 #ifndef WIN32
208   pthread_cond_init(&cond, NULL);
209 #else
210    cond = CreateEvent(NULL,/*FALSE*/TRUE,FALSE,NULL);
211 #endif
212 }
213
214 EDReceiver::~EDReceiver()
215 {
216 #ifdef WIN32
217   if (cond!=NULL) CloseHandle(cond);
218 #else
219   pthread_cond_destroy(&cond);
220 #endif
221 }