updates.
[crypto.git] / lib / silcutil / unix / silcunixschedule.c
1 /*
2
3   silcunixschedule.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 1998 - 2001 Pekka Riikonen
8
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.
13   
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.
18
19 */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23 #include "silcschedule_i.h"
24
25 /* Calls normal select() system call. */
26
27 int silc_select(SilcScheduleFd fds, SilcUInt32 fds_count, 
28                 struct timeval *timeout)
29 {
30   fd_set in, out;
31   int ret, i, max_fd = 0;
32
33   FD_ZERO(&in);
34   FD_ZERO(&out);
35
36   for (i = 0; i < fds_count; i++) {
37     if (!fds[i].events)
38       continue;
39
40     if (fds[i].fd > max_fd)
41       max_fd = fds[i].fd;
42
43     if (fds[i].events & SILC_TASK_READ)
44       FD_SET(fds[i].fd, &in);
45     if (fds[i].events & SILC_TASK_WRITE)
46       FD_SET(fds[i].fd, &out);
47
48     fds[i].revents = 0;
49   }
50
51   ret = select(max_fd + 1, &in, &out, NULL, timeout);
52   if (ret <= 0)
53     return ret;
54
55   for (i = 0; i < fds_count; i++) {
56     if (!fds[i].events)
57       continue;
58
59     if (FD_ISSET(fds[i].fd, &in))
60       fds[i].revents |= SILC_TASK_READ;
61     if (FD_ISSET(fds[i].fd, &out))
62       fds[i].revents |= SILC_TASK_WRITE;
63   }
64
65   return ret;
66 }
67
68 #ifdef SILC_THREADS
69
70 /* Internal wakeup context. */
71 typedef struct {
72   int wakeup_pipe[2];
73   SilcTask wakeup_task;
74 } *SilcUnixWakeup;
75
76 SILC_TASK_CALLBACK(silc_schedule_wakeup_cb)
77 {
78   SilcUnixWakeup wakeup = (SilcUnixWakeup)context;
79   unsigned char c;
80
81   read(wakeup->wakeup_pipe[0], &c, 1);
82 }
83
84 #endif /* SILC_THREADS */
85
86 /* Initializes the wakeup of the scheduler. In multi-threaded environment
87    the scheduler needs to be wakenup when tasks are added or removed from
88    the task queues. This will initialize the wakeup for the scheduler.
89    Any tasks that needs to be registered must be registered to the `queue'.
90    It is quaranteed that the scheduler will automatically free any
91    registered tasks in this queue. This is system specific routine. */
92
93 void *silc_schedule_wakeup_init(SilcSchedule schedule)
94 {
95 #ifdef SILC_THREADS
96   SilcUnixWakeup wakeup;
97
98   wakeup = silc_calloc(1, sizeof(*wakeup));
99
100   if (pipe(wakeup->wakeup_pipe)) {
101     silc_free(wakeup);
102     return NULL;
103   }
104
105   wakeup->wakeup_task = 
106     silc_schedule_task_add(schedule, wakeup->wakeup_pipe[0],
107                            silc_schedule_wakeup_cb, wakeup,
108                            0, 0, SILC_TASK_FD, 
109                            SILC_TASK_PRI_NORMAL);
110   if (!wakeup->wakeup_task) {
111     close(wakeup->wakeup_pipe[0]);
112     close(wakeup->wakeup_pipe[1]);
113     silc_free(wakeup);
114     return NULL;
115   }
116
117   return (void *)wakeup;
118 #endif
119   return NULL;
120 }
121
122 /* Uninitializes the system specific wakeup. */
123
124 void silc_schedule_wakeup_uninit(void *context)
125 {
126 #ifdef SILC_THREADS
127   SilcUnixWakeup wakeup = (SilcUnixWakeup)context;
128
129   if (!wakeup)
130     return;
131
132   close(wakeup->wakeup_pipe[0]);
133   close(wakeup->wakeup_pipe[1]);
134   silc_free(wakeup);
135 #endif
136 }
137
138 /* Wakes up the scheduler */
139
140 void silc_schedule_wakeup_internal(void *context)
141 {
142 #ifdef SILC_THREADS
143   SilcUnixWakeup wakeup = (SilcUnixWakeup)context;
144
145   if (!wakeup)
146     return;
147
148   write(wakeup->wakeup_pipe[1], "!", 1);
149 #endif
150 }