]> git.vomp.tv Git - vompclient.git/blob - eventdispatcher.cc
Improve connection failure handling
[vompclient.git] / eventdispatcher.cc
1 /*
2     Copyright 2007-2020 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, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include "eventdispatcher.h"
21
22 void EventDispatcher::edRegister(EDReceiver* edr)
23 {
24   edMutex.lock();
25   receivers.push_back(edr);
26   edMutex.unlock();
27 }  
28
29 bool EventDispatcher::edFindAndCall(void* userTag)
30 {
31   edMutex.lock();
32   
33   EDReceiver* edr = NULL;
34   EDRL::iterator i;
35   for(i = receivers.begin(); i != receivers.end(); i++)
36   {
37     if (ed_cb_find(*i, userTag))
38     {
39       edr = *i;
40       break; // found (by asking the EventDispatcher implementor to check if userTag is for *i
41     }
42   }
43   
44   if ((i == receivers.end()) || edr->callinprogress || edr->nomorecalls)
45   {
46     edMutex.unlock();
47     return false;
48   }
49   
50   edr->callinprogress = true;
51   edMutex.unlock();
52   bool r_deregisterEDR = false;
53   bool r_wakeThread = false;
54   bool r_deleteEDR = false;
55   edr->call(userTag, r_deregisterEDR, r_wakeThread, r_deleteEDR);
56   edMutex.lock();
57   edr->callinprogress = false;
58
59
60   // if it's a stream packet (r_deregisterEDR == false)
61   // and edr->nomorecalls == true
62   // then something has called unregister for this EDR while we were out on the call
63   // set r_wakeThread to ensure that we signal the edr->cond to wake up that thread in edUnregister below
64   if ((r_deregisterEDR == false) && (edr->nomorecalls))
65   {
66     r_wakeThread = true;
67   }
68
69   if (r_deregisterEDR)
70   {
71     for(i = receivers.begin(); i != receivers.end(); i++)
72     {
73       if (*i == edr)
74       {
75         receivers.erase(i);
76         break;
77       }
78     }
79     #ifndef WIN32
80     if (i == receivers.end()) abort(); // should never happen
81     // but it can happen under windows ... how??
82     #endif
83   }
84
85   if (r_wakeThread)
86   {
87     edr->cond.notify_one();
88   }
89
90   if (r_deleteEDR)
91   {
92     delete edr;
93   }
94   
95   edMutex.unlock();
96   return true;
97 }
98
99 void EventDispatcher::edUnregister(EDReceiver* edr)
100 {
101   std::unique_lock<std::mutex> ul(edMutex);
102
103   EDRL::iterator i;
104   for(i = receivers.begin(); i != receivers.end(); i++)
105   {
106     if (*i == edr) break; // found
107   }
108
109   // Not in the list. Already unregistered? Perhaps vdr::connectionDied already removed this streamclient
110   // 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.
111   if (i == receivers.end()) return;
112
113   if (!edr->callinprogress)
114   {
115     receivers.erase(i);
116     return;
117   }
118
119   edr->nomorecalls = true;
120   
121   // edUnlock, wait for callinprogres=false (cond to be signalled), lock  
122   edr->cond.wait(ul);
123
124   for(i = receivers.begin(); i != receivers.end(); i++)
125   {
126     if (*i == edr) break; // found
127   }
128
129   if (i == receivers.end()) abort(); // should never happen
130
131   receivers.erase(i);
132 }
133
134 // ---------------------------------------
135
136 void EventDispatcher::edSleepThisReceiver(EDReceiver* edr)
137 {
138   // For blocking version, not callback version. Call with edLock locked
139   std::unique_lock<std::mutex> ul(edMutex, std::defer_lock);
140   edr->cond.wait(ul);
141 }