1 | /********** |
2 | This library is free software; you can redistribute it and/or modify it under |
3 | the terms of the GNU Lesser General Public License as published by the |
4 | Free Software Foundation; either version 3 of the License, or (at your |
5 | option) any later version. (See <http://www.gnu.org/copyleft/lesser.html>.) |
6 | |
7 | This library is distributed in the hope that it will be useful, but WITHOUT |
8 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
9 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for |
10 | more details. |
11 | |
12 | You should have received a copy of the GNU Lesser General Public License |
13 | along with this library; if not, write to the Free Software Foundation, Inc., |
14 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
15 | **********/ |
16 | // Copyright (c) 1996-2020 Live Networks, Inc. All rights reserved. |
17 | // Basic Usage Environment: for a simple, non-scripted, console application |
18 | // Implementation |
19 | |
20 | #include "BasicUsageEnvironment0.hh" |
21 | #include "HandlerSet.hh" |
22 | |
23 | ////////// A subclass of DelayQueueEntry, |
24 | ////////// used to implement BasicTaskScheduler0::scheduleDelayedTask() |
25 | |
26 | class AlarmHandler: public DelayQueueEntry { |
27 | public: |
28 | AlarmHandler(TaskFunc* proc, void* clientData, DelayInterval timeToDelay) |
29 | : DelayQueueEntry(timeToDelay), fProc(proc), fClientData(clientData) { |
30 | } |
31 | |
32 | private: // redefined virtual functions |
33 | virtual void handleTimeout() { |
34 | (*fProc)(fClientData); |
35 | DelayQueueEntry::handleTimeout(); |
36 | } |
37 | |
38 | private: |
39 | TaskFunc* fProc; |
40 | void* fClientData; |
41 | }; |
42 | |
43 | |
44 | ////////// BasicTaskScheduler0 ////////// |
45 | |
46 | BasicTaskScheduler0::BasicTaskScheduler0() |
47 | : fLastHandledSocketNum(-1), fTriggersAwaitingHandling(0), fLastUsedTriggerMask(1), fLastUsedTriggerNum(MAX_NUM_EVENT_TRIGGERS-1) { |
48 | fHandlers = new HandlerSet; |
49 | for (unsigned i = 0; i < MAX_NUM_EVENT_TRIGGERS; ++i) { |
50 | fTriggeredEventHandlers[i] = NULL; |
51 | fTriggeredEventClientDatas[i] = NULL; |
52 | } |
53 | } |
54 | |
55 | BasicTaskScheduler0::~BasicTaskScheduler0() { |
56 | delete fHandlers; |
57 | } |
58 | |
59 | TaskToken BasicTaskScheduler0::scheduleDelayedTask(int64_t microseconds, |
60 | TaskFunc* proc, |
61 | void* clientData) { |
62 | if (microseconds < 0) microseconds = 0; |
63 | DelayInterval timeToDelay((long)(microseconds/1000000), (long)(microseconds%1000000)); |
64 | AlarmHandler* alarmHandler = new AlarmHandler(proc, clientData, timeToDelay); |
65 | fDelayQueue.addEntry(alarmHandler); |
66 | |
67 | return (void*)(alarmHandler->token()); |
68 | } |
69 | |
70 | void BasicTaskScheduler0::unscheduleDelayedTask(TaskToken& prevTask) { |
71 | DelayQueueEntry* alarmHandler = fDelayQueue.removeEntry((intptr_t)prevTask); |
72 | prevTask = NULL; |
73 | delete alarmHandler; |
74 | } |
75 | |
76 | void BasicTaskScheduler0::doEventLoop(char volatile* watchVariable) { |
77 | // Repeatedly loop, handling readble sockets and timed events: |
78 | while (1) { |
79 | if (watchVariable != NULL && *watchVariable != 0) break; |
80 | SingleStep(); |
81 | } |
82 | } |
83 | |
84 | EventTriggerId BasicTaskScheduler0::createEventTrigger(TaskFunc* eventHandlerProc) { |
85 | unsigned i = fLastUsedTriggerNum; |
86 | EventTriggerId mask = fLastUsedTriggerMask; |
87 | |
88 | do { |
89 | i = (i+1)%MAX_NUM_EVENT_TRIGGERS; |
90 | mask >>= 1; |
91 | if (mask == 0) mask = 0x80000000; |
92 | |
93 | if (fTriggeredEventHandlers[i] == NULL) { |
94 | // This trigger number is free; use it: |
95 | fTriggeredEventHandlers[i] = eventHandlerProc; |
96 | fTriggeredEventClientDatas[i] = NULL; // sanity |
97 | |
98 | fLastUsedTriggerMask = mask; |
99 | fLastUsedTriggerNum = i; |
100 | |
101 | return mask; |
102 | } |
103 | } while (i != fLastUsedTriggerNum); |
104 | |
105 | // All available event triggers are allocated; return 0 instead: |
106 | return 0; |
107 | } |
108 | |
109 | void BasicTaskScheduler0::deleteEventTrigger(EventTriggerId eventTriggerId) { |
110 | fTriggersAwaitingHandling &=~ eventTriggerId; |
111 | |
112 | if (eventTriggerId == fLastUsedTriggerMask) { // common-case optimization: |
113 | fTriggeredEventHandlers[fLastUsedTriggerNum] = NULL; |
114 | fTriggeredEventClientDatas[fLastUsedTriggerNum] = NULL; |
115 | } else { |
116 | // "eventTriggerId" should have just one bit set. |
117 | // However, we do the reasonable thing if the user happened to 'or' together two or more "EventTriggerId"s: |
118 | EventTriggerId mask = 0x80000000; |
119 | for (unsigned i = 0; i < MAX_NUM_EVENT_TRIGGERS; ++i) { |
120 | if ((eventTriggerId&mask) != 0) { |
121 | fTriggeredEventHandlers[i] = NULL; |
122 | fTriggeredEventClientDatas[i] = NULL; |
123 | } |
124 | mask >>= 1; |
125 | } |
126 | } |
127 | } |
128 | |
129 | void BasicTaskScheduler0::triggerEvent(EventTriggerId eventTriggerId, void* clientData) { |
130 | // First, record the "clientData". (Note that we allow "eventTriggerId" to be a combination of bits for multiple events.) |
131 | EventTriggerId mask = 0x80000000; |
132 | for (unsigned i = 0; i < MAX_NUM_EVENT_TRIGGERS; ++i) { |
133 | if ((eventTriggerId&mask) != 0) { |
134 | fTriggeredEventClientDatas[i] = clientData; |
135 | } |
136 | mask >>= 1; |
137 | } |
138 | |
139 | // Then, note this event as being ready to be handled. |
140 | // (Note that because this function (unlike others in the library) can be called from an external thread, we do this last, to |
141 | // reduce the risk of a race condition.) |
142 | fTriggersAwaitingHandling |= eventTriggerId; |
143 | } |
144 | |
145 | |
146 | ////////// HandlerSet (etc.) implementation ////////// |
147 | |
148 | HandlerDescriptor::HandlerDescriptor(HandlerDescriptor* nextHandler) |
149 | : conditionSet(0), handlerProc(NULL) { |
150 | // Link this descriptor into a doubly-linked list: |
151 | if (nextHandler == this) { // initialization |
152 | fNextHandler = fPrevHandler = this; |
153 | } else { |
154 | fNextHandler = nextHandler; |
155 | fPrevHandler = nextHandler->fPrevHandler; |
156 | nextHandler->fPrevHandler = this; |
157 | fPrevHandler->fNextHandler = this; |
158 | } |
159 | } |
160 | |
161 | HandlerDescriptor::~HandlerDescriptor() { |
162 | // Unlink this descriptor from a doubly-linked list: |
163 | fNextHandler->fPrevHandler = fPrevHandler; |
164 | fPrevHandler->fNextHandler = fNextHandler; |
165 | } |
166 | |
167 | HandlerSet::HandlerSet() |
168 | : fHandlers(&fHandlers) { |
169 | fHandlers.socketNum = -1; // shouldn't ever get looked at, but in case... |
170 | } |
171 | |
172 | HandlerSet::~HandlerSet() { |
173 | // Delete each handler descriptor: |
174 | while (fHandlers.fNextHandler != &fHandlers) { |
175 | delete fHandlers.fNextHandler; // changes fHandlers->fNextHandler |
176 | } |
177 | } |
178 | |
179 | void HandlerSet |
180 | ::assignHandler(int socketNum, int conditionSet, TaskScheduler::BackgroundHandlerProc* handlerProc, void* clientData) { |
181 | // First, see if there's already a handler for this socket: |
182 | HandlerDescriptor* handler = lookupHandler(socketNum); |
183 | if (handler == NULL) { // No existing handler, so create a new descr: |
184 | handler = new HandlerDescriptor(fHandlers.fNextHandler); |
185 | handler->socketNum = socketNum; |
186 | } |
187 | |
188 | handler->conditionSet = conditionSet; |
189 | handler->handlerProc = handlerProc; |
190 | handler->clientData = clientData; |
191 | } |
192 | |
193 | void HandlerSet::clearHandler(int socketNum) { |
194 | HandlerDescriptor* handler = lookupHandler(socketNum); |
195 | delete handler; |
196 | } |
197 | |
198 | void HandlerSet::moveHandler(int oldSocketNum, int newSocketNum) { |
199 | HandlerDescriptor* handler = lookupHandler(oldSocketNum); |
200 | if (handler != NULL) { |
201 | handler->socketNum = newSocketNum; |
202 | } |
203 | } |
204 | |
205 | HandlerDescriptor* HandlerSet::lookupHandler(int socketNum) { |
206 | HandlerDescriptor* handler; |
207 | HandlerIterator iter(*this); |
208 | while ((handler = iter.next()) != NULL) { |
209 | if (handler->socketNum == socketNum) break; |
210 | } |
211 | return handler; |
212 | } |
213 | |
214 | HandlerIterator::HandlerIterator(HandlerSet& handlerSet) |
215 | : fOurSet(handlerSet) { |
216 | reset(); |
217 | } |
218 | |
219 | HandlerIterator::~HandlerIterator() { |
220 | } |
221 | |
222 | void HandlerIterator::reset() { |
223 | fNextPtr = fOurSet.fHandlers.fNextHandler; |
224 | } |
225 | |
226 | HandlerDescriptor* HandlerIterator::next() { |
227 | HandlerDescriptor* result = fNextPtr; |
228 | if (result == &fOurSet.fHandlers) { // no more |
229 | result = NULL; |
230 | } else { |
231 | fNextPtr = fNextPtr->fNextHandler; |
232 | } |
233 | |
234 | return result; |
235 | } |
236 | |