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()
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 /* Wakeup scheduler */
121 iStatus = KRequestPending;
125 virtual void DoCancel()
132 SilcSymbianScheduler *timer;
133 unsigned int wake_signal : 1;
138 /* Symbian's silc_schedule call. We start Active Scheduler here and start
139 our SILC Scheduler. The calling thread will block here. */
141 void silc_schedule(SilcSchedule schedule)
143 SilcSymbianInternal internal = (SilcSymbianInternal)schedule->internal;
144 CActiveSchedulerWait *s;
146 SILC_LOG_DEBUG(("Running scheduler"));
148 /* Create Active Scheduler */
149 s = new CActiveSchedulerWait;
152 /* Start SILC Scheduler */
153 internal->timer = new SilcSymbianScheduler;
154 SILC_ASSERT(internal->timer);
155 internal->timer->schedule = schedule;
156 internal->timer->s = s;
157 internal->wakeup = new SilcSymbianSchedulerWakeup;
158 SILC_ASSERT(internal->wakeup);
159 internal->wakeup->id = RThread().Id();
160 internal->wakeup->thread.Open(internal->wakeup->id);
161 internal->wakeup->timer = internal->timer;
163 /* Start Active Scheduler */
166 delete internal->wakeup;
167 delete internal->timer;
171 int silc_poll(SilcSchedule schedule, void *context)
173 SilcSymbianInternal internal = (SilcSymbianInternal)context;
177 /* When user is using silc_schedule_one we don't have our timer set,
178 so just return immediately. */
179 if (!internal->timer)
182 /* Schedule next timeout */
183 if (schedule->has_timeout)
184 timeout = ((schedule->timeout.tv_sec * 1000) +
185 (schedule->timeout.tv_usec / 1000));
193 /* Set the timeout value */
194 at_timeout.HomeTime();
195 while (timeout > 2100 * 1000) {
196 at_timeout += (TTimeIntervalMicroSeconds32)(2100 * 1000 * 1000);
197 timeout -= (2100 * 1000);
199 at_timeout += (TTimeIntervalMicroSeconds32)timeout;
201 /* Schedule the timeout */
202 internal->timer->At(at_timeout);
204 /* Return special "ignore" value. Causes the scheduler to just break
205 the scheduler iteration and return back to its caller. */
209 SilcBool silc_schedule_internal_schedule_fd(SilcSchedule schedule,
212 SilcTaskEvent event_mask)
218 void *silc_schedule_internal_init(SilcSchedule schedule,
221 SilcSymbianInternal internal;
223 internal = (SilcSymbianInternal)silc_calloc(1, sizeof(*internal));
230 void silc_schedule_internal_uninit(SilcSchedule schedule, void *context)
232 SilcSymbianInternal internal = (SilcSymbianInternal)context;
236 void silc_schedule_internal_wakeup(SilcSchedule schedule, void *context)
239 SilcSymbianInternal internal = (SilcSymbianInternal)context;
242 if (!internal->timer)
246 internal->wakeup->Wakeup(id);
247 #endif /* SILC_THREADS */
250 void silc_schedule_internal_signal_register(SilcSchedule schedule,
253 SilcTaskCallback callback,
254 void *callback_context)
259 void silc_schedule_internal_signal_unregister(SilcSchedule schedule,
266 void silc_schedule_internal_signals_call(SilcSchedule schedule, void *context)
271 void silc_schedule_internal_signals_block(SilcSchedule schedule, void *context)
276 void silc_schedule_internal_signals_unblock(SilcSchedule schedule,
282 EXPORT_C const SilcScheduleOps schedule_ops =
284 silc_schedule_internal_init,
285 silc_schedule_internal_uninit,
287 silc_schedule_internal_schedule_fd,
288 silc_schedule_internal_wakeup,
289 silc_schedule_internal_signal_register,
290 silc_schedule_internal_signal_unregister,
291 silc_schedule_internal_signals_call,
292 silc_schedule_internal_signals_block,
293 silc_schedule_internal_signals_unblock,