5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 2001 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; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
22 #include "silcincludes.h"
23 #include "silcschedule_i.h"
25 /* Our "select()" for WIN32. This mimics the behaviour of select() system
26 call. It does not call the Winsock's select() though. Its functions
27 are derived from GLib's g_poll() and from some old Xemacs's sys_select().
29 This makes following assumptions, which I don't know whether they
32 o SILC_TASK_WRITE is ignored, if set this will return immediately.
33 o If all arguments except timeout are NULL then this will register
34 a timeout with SetTimer and will wait just for Windows messages
36 o MsgWaitForMultipleObjects is used to wait all kind of events, this
37 includes SOCKETs and Windows messages.
38 o All Windows messages are dispatched from this function.
39 o The Operating System has Winsock 2.
43 o http://msdn.microsoft.com/library/default.asp?
44 url=/library/en-us/winui/hh/winui/messques_77zk.asp
45 o http://msdn.microsoft.com/library/default.asp?
46 url=/library/en-us/winsock/hh/winsock/apistart_9g1e.asp
47 o http://msdn.microsoft.com/library/default.asp?
48 url=/library/en-us/dnmgmt/html/msdn_getpeek.asp
49 o http://developer.novell.com/support/winsock/doc/toc.htm
53 int silc_select(SilcScheduleFd fds, uint32 fds_count, struct timeval *timeout)
55 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
56 DWORD ready, curtime, timeo;
60 if (fds_count > MAXIMUM_WAIT_OBJECTS)
61 fds_count = MAXIMUM_WAIT_OBJECTS;
63 for (i = 0; i < fds_count; i++) {
67 if (fds[i].events & SILC_TASK_READ)
68 handles[nhandles++] = (HANDLE)fds[i].fd;
70 /* If writing then just set the bit and return */
71 if (fds[i].events & SILC_TASK_WRITE) {
72 fds[i].revents = SILC_TASK_WRITE;
79 timeo = (timeout ? (timeout->tv_sec * 1000) + (timeout->tv_usec / 1000) :
82 /* If we have nothing to wait and timeout is set then register a timeout
83 and wait just for windows messages. */
84 if (nhandles == 0 && timeout) {
85 UINT timer = SetTimer(NULL, 0, timeo, NULL);
86 curtime = GetTickCount();
90 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
91 if (msg.message == WM_TIMER) {
92 KillTimer(NULL, timer);
95 TranslateMessage(&msg);
96 DispatchMessage(&msg);
99 KillTimer(NULL, timer);
100 if (timeo != INFINITE) {
101 timeo -= GetTickCount() - curtime;
105 timer = SetTimer(NULL, 0, timeo, NULL);
110 curtime = GetTickCount();
111 ready = MsgWaitForMultipleObjects(nhandles, handles, FALSE, timeo,
114 if (ready == WAIT_FAILED) {
115 /* Wait failed with error */
116 SILC_LOG_WARNING(("WaitForMultipleObjects() failed"));
118 } else if (ready >= WAIT_ABANDONED_0 &&
119 ready < WAIT_ABANDONED_0 + nhandles) {
120 /* Signal abandoned */
121 SILC_LOG_WARNING(("WaitForMultipleObjects() failed (ABANDONED)"));
123 } else if (ready == WAIT_TIMEOUT) {
126 } else if (ready == WAIT_OBJECT_0 + nhandles) {
127 /* Windows messages. The MSDN online says that if the application
128 creates a window then its main loop (and we're assuming that
129 it is our SILC Scheduler) must handle the Windows messages, so do
130 it here as the MSDN suggests. */
131 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
132 TranslateMessage(&msg);
133 DispatchMessage(&msg);
136 /* If timeout is set then we must update the timeout since we won't
137 return and we will give the wait another try. */
138 if (timeo != INFINITE) {
139 timeo -= GetTickCount() - curtime;
144 /* Give the wait another try */
146 } else if (ready >= WAIT_OBJECT_0 && ready < WAIT_OBJECT_0 + nhandles) {
147 /* Some other event, like SOCKET or something. */
149 /* Go through all fds even though only one was set. This is to avoid
150 starvation of high numbered fds. */
151 ready -= WAIT_OBJECT_0;
153 for (i = 0; i < fds_count; i++) {
157 if (fds[i].fd == (int)handles[ready]) {
158 fds[i].revents |= SILC_TASK_READ;
163 /* Check the status of the next handle and set its fd to the fd
164 set if data is available. */
165 while (++ready < fds_count)
166 if (WaitForSingleObject(handles[ready], 0) == WAIT_OBJECT_0)
168 } while (ready < fds_count);
178 /* Internal wakeup context. */
181 SilcTask wakeup_task;
184 SILC_TASK_CALLBACK(silc_schedule_wakeup_cb)
189 #endif /* SILC_THREADS */
191 /* Initializes the wakeup of the scheduler. In multi-threaded environment
192 the scheduler needs to be wakenup when tasks are added or removed from
193 the task queues. This will initialize the wakeup for the scheduler.
194 Any tasks that needs to be registered must be registered to the `queue'.
195 It is guaranteed that the scheduler will automatically free any
196 registered tasks in this queue. This is system specific routine. */
198 void *silc_schedule_wakeup_init(SilcSchedule schedule)
201 SilcWin32Wakeup wakeup;
203 wakeup = silc_calloc(1, sizeof(*wakeup));
205 wakeup->wakeup_sema = CreateSemaphore(NULL, 0, 100, NULL);
206 if (!wakeup->wakeup_sema) {
211 wakeup->wakeup_task =
212 silc_schedule_task_add(schedule, (int)wakeup->wakeup_sema,
213 silc_schedule_wakeup_cb, wakeup,
215 SILC_TASK_PRI_NORMAL);
216 if (!wakeup->wakeup_task) {
217 CloseHandle(wakeup->wakeup_sema);
222 return (void *)wakeup;
228 /* Uninitializes the system specific wakeup. */
230 void silc_schedule_wakeup_uninit(void *context)
233 SilcWin32Wakeup wakeup = (SilcWin32Wakeup)context;
238 CloseHandle(wakeup->wakeup_sema);
243 /* Wakes up the scheduler */
245 void silc_schedule_wakeup_internal(void *context)
248 SilcWin32Wakeup wakeup = (SilcWin32Wakeup)context;
253 ReleaseSemaphore(wakeup->wakeup_sema, 1, NULL);