3 silcsymbianscheduler.cpp
5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2007 Pekka Riikonen
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
23 /* The SILC Scheduler for Symbian handles only timeout tasks. Fd tasks are
24 not handled by the SILC Scheduler at all but are handled by the Symbian's
25 Active Scheduler. Fd and socket stream callbacks are delivered back
26 to caller in their respective class implementatios.
28 The SILC Scheduler in Symbian works by creating CActiveSchedulerWait
29 when silc_schedule() is called. This will block the calling thread just
30 like silc_schedule is supposed to do. Under that Active Scheduler we
31 run our SilcSymbianScheduler timer which will handle the actual SILC
32 Scheduler by calling silc_schedule_one at correct times. The timeout
33 values are selected by the SILC Scheduler itself when silc_schedule_one
34 is called. After that call returns we go back to the Active Scheduler
35 to dispatch other active objects and to wait for next timeout.
37 Wakeup of the scheduler works by simply cancelling the outstanding timeout
38 and issuing a zero timeout to call the silc_schedule_one again.
40 If user directly calls silc_schedule_one it behaves same as on other
43 class SilcSymbianScheduler;
44 class SilcSymbianSchedulerWakeup;
47 SilcSymbianScheduler *timer;
48 SilcSymbianSchedulerWakeup *wakeup;
49 } *SilcSymbianInternal;
51 /* SILC scheduler timer class. This handles the actual SILC Scheduler
52 by calling silc_schedule_one and scheduling the scheduler timeouts. */
53 class SilcSymbianScheduler : public CTimer {
56 SilcSymbianScheduler() : CTimer(CActive::EPriorityStandard)
59 CActiveScheduler::Add(this);
64 ~SilcSymbianScheduler()
69 /* Timeout callback */
72 if (!silc_schedule_one(schedule, -1))
76 CActiveSchedulerWait *s;
77 SilcSchedule schedule;
80 /* Scheduler wakeup class */
81 class SilcSymbianSchedulerWakeup : public CActive {
84 SilcSymbianSchedulerWakeup() : CActive(CActive::EPriorityStandard)
86 CActiveScheduler::Add(this);
87 iStatus = KRequestPending;
92 ~SilcSymbianSchedulerWakeup()
97 /* Wakeup. This is called with scheduler locked. */
98 void Wakeup(TThreadId thread_id)
104 TRequestStatus *status = &iStatus;
106 thread.RequestComplete(status, KErrNone);
108 User::RequestComplete(status, KErrNone);
111 /* Timeout callback */
114 SILC_LOG_DEBUG(("Wakeup scheduler"));
116 /* We need to synchronize with calls to Wakeup() */
117 silc_mutex_lock(schedule->lock);
119 /* Wakeup scheduler */
124 iStatus = KRequestPending;
127 silc_mutex_unlock(schedule->lock);
130 virtual void DoCancel()
137 SilcSymbianScheduler *timer;
138 SilcSchedule schedule;
139 unsigned int wake_signal : 1;
144 /* Symbian's silc_schedule call. We start Active Scheduler here and start
145 our SILC Scheduler. The calling thread will block here. */
147 void silc_schedule(SilcSchedule schedule)
149 SilcSymbianInternal internal = (SilcSymbianInternal)schedule->internal;
150 CActiveSchedulerWait *s;
152 SILC_LOG_DEBUG(("Running scheduler"));
154 /* Create Active Scheduler */
155 s = new CActiveSchedulerWait;
158 /* Start SILC Scheduler */
159 internal->timer = new SilcSymbianScheduler;
160 SILC_ASSERT(internal->timer);
161 internal->timer->schedule = schedule;
162 internal->timer->s = s;
163 internal->wakeup = new SilcSymbianSchedulerWakeup;
164 SILC_ASSERT(internal->wakeup);
165 internal->wakeup->id = RThread().Id();
166 internal->wakeup->thread.Open(internal->wakeup->id);
167 internal->wakeup->timer = internal->timer;
168 internal->wakeup->schedule = schedule;
170 /* Start Active Scheduler */
173 delete internal->wakeup;
174 delete internal->timer;
178 int silc_poll(SilcSchedule schedule, void *context)
180 SilcSymbianInternal internal = (SilcSymbianInternal)context;
184 /* When user is using silc_schedule_one we don't have our timer set,
185 so just return immediately. */
186 if (!internal->timer)
189 /* Schedule next timeout */
190 if (schedule->has_timeout)
191 timeout = ((schedule->timeout.tv_sec * 1000) +
192 (schedule->timeout.tv_usec / 1000));
200 /* Set the timeout value */
201 at_timeout.HomeTime();
202 while (timeout > 2100 * 1000) {
203 at_timeout += (TTimeIntervalMicroSeconds32)(2100 * 1000 * 1000);
204 timeout -= (2100 * 1000);
206 at_timeout += (TTimeIntervalMicroSeconds32)(timeout * 1000);
208 /* Schedule the timeout */
209 if (internal->timer->IsActive())
210 internal->timer->Cancel();
211 internal->timer->At(at_timeout);
213 /* Return special "ignore" value. Causes the scheduler to just break
214 the scheduler iteration and return back to its caller. */
218 SilcBool silc_schedule_internal_schedule_fd(SilcSchedule schedule,
221 SilcTaskEvent event_mask)
227 void *silc_schedule_internal_init(SilcSchedule schedule,
230 SilcSymbianInternal internal;
232 internal = (SilcSymbianInternal)silc_calloc(1, sizeof(*internal));
239 void silc_schedule_internal_uninit(SilcSchedule schedule, void *context)
241 SilcSymbianInternal internal = (SilcSymbianInternal)context;
245 void silc_schedule_internal_wakeup(SilcSchedule schedule, void *context)
248 SilcSymbianInternal internal = (SilcSymbianInternal)context;
251 if (!internal->timer)
255 internal->wakeup->Wakeup(id);
256 #endif /* SILC_THREADS */
259 void silc_schedule_internal_signal_register(SilcSchedule schedule,
262 SilcTaskCallback callback,
263 void *callback_context)
268 void silc_schedule_internal_signal_unregister(SilcSchedule schedule,
275 void silc_schedule_internal_signals_call(SilcSchedule schedule, void *context)
280 void silc_schedule_internal_signals_block(SilcSchedule schedule, void *context)
285 void silc_schedule_internal_signals_unblock(SilcSchedule schedule,
292 EXPORT_C const SilcScheduleOps schedule_ops =
294 const SilcScheduleOps schedule_ops =
295 #endif /* __WINSCW__ */
297 silc_schedule_internal_init,
298 silc_schedule_internal_uninit,
300 silc_schedule_internal_schedule_fd,
301 silc_schedule_internal_wakeup,
302 silc_schedule_internal_signal_register,
303 silc_schedule_internal_signal_unregister,
304 silc_schedule_internal_signals_call,
305 silc_schedule_internal_signals_block,
306 silc_schedule_internal_signals_unblock,