@matheusbsbs / matheus-bagliano / commits / 6072fc314e
Fork 0

Windows: Implement setitimer() and sigaction().

The timer is implemented using a thread that calls the signal handler at regular intervals. We also replace Windows's signal() function because we must intercept that SIGALRM is set (which is used when a timer is canceled). Signed-off-by: Johannes Sixt <johannes.sixt@telecom.at>

Johannes Sixt committed Nov 13, 2007 at 10:14 UTC 6072fc314e87d53bec7266df5b6c3db2c2c82829
2 files changed +113 -2
compat/mingw.c
+110 -2
@@ -125,12 +125,120 @@ struct passwd *getpwuid(int uid)
125 return &p;
126 }
127
128 +static HANDLE timer_event;
129 +static HANDLE timer_thread;
130 +static int timer_interval;
131 +static int one_shot;
132 +static sig_handler_t timer_fn = SIG_DFL;
133 +
134 +/* The timer works like this:
135 + * The thread, ticktack(), is a trivial routine that most of the time
136 + * only waits to receive the signal to terminate. The main thread tells
137 + * the thread to terminate by setting the timer_event to the signalled
138 + * state.
139 + * But ticktack() interrupts the wait state after the timer's interval
140 + * length to call the signal handler.
141 + */
142 +
143 +static __stdcall unsigned ticktack(void *dummy)
144 +{
145 + while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
146 + if (timer_fn == SIG_DFL)
147 + die("Alarm");
148 + if (timer_fn != SIG_IGN)
149 + timer_fn(SIGALRM);
150 + if (one_shot)
151 + break;
152 + }
153 + return 0;
154 +}
155 +
156 +static int start_timer_thread(void)
157 +{
158 + timer_event = CreateEvent(NULL, FALSE, FALSE, NULL);
159 + if (timer_event) {
160 + timer_thread = (HANDLE) _beginthreadex(NULL, 0, ticktack, NULL, 0, NULL);
161 + if (!timer_thread )
162 + return errno = ENOMEM,
163 + error("cannot start timer thread");
164 + } else
165 + return errno = ENOMEM,
166 + error("cannot allocate resources for timer");
167 + return 0;
168 +}
169 +
170 +static void stop_timer_thread(void)
171 +{
172 + if (timer_event)
173 + SetEvent(timer_event); /* tell thread to terminate */
174 + if (timer_thread) {
175 + int rc = WaitForSingleObject(timer_thread, 1000);
176 + if (rc == WAIT_TIMEOUT)
177 + error("timer thread did not terminate timely");
178 + else if (rc != WAIT_OBJECT_0)
179 + error("waiting for timer thread failed: %lu",
180 + GetLastError());
181 + CloseHandle(timer_thread);
182 + }
183 + if (timer_event)
184 + CloseHandle(timer_event);
185 + timer_event = NULL;
186 + timer_thread = NULL;
187 +}
188 +
189 +static inline int is_timeval_eq(const struct timeval *i1, const struct timeval *i2)
190 +{
191 + return i1->tv_sec == i2->tv_sec && i1->tv_usec == i2->tv_usec;
192 +}
193 +
194 int setitimer(int type, struct itimerval *in, struct itimerval *out)
195 {
130 - return -1;
196 + static const struct timeval zero;
197 + static int atexit_done;
198 +
199 + if (out != NULL)
200 + return errno = EINVAL,
201 + error("setitimer param 3 != NULL not implemented");
202 + if (!is_timeval_eq(&in->it_interval, &zero) &&
203 + !is_timeval_eq(&in->it_interval, &in->it_value))
204 + return errno = EINVAL,
205 + error("setitimer: it_interval must be zero or eq it_value");
206 +
207 + if (timer_thread)
208 + stop_timer_thread();
209 +
210 + if (is_timeval_eq(&in->it_value, &zero) &&
211 + is_timeval_eq(&in->it_interval, &zero))
212 + return 0;
213 +
214 + timer_interval = in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000;
215 + one_shot = is_timeval_eq(&in->it_interval, &zero);
216 + if (!atexit_done) {
217 + atexit(stop_timer_thread);
218 + atexit_done = 1;
219 + }
220 + return start_timer_thread();
221 }
222
223 int sigaction(int sig, struct sigaction *in, struct sigaction *out)
224 {
135 - return -1;
225 + if (sig != SIGALRM)
226 + return errno = EINVAL,
227 + error("sigaction only implemented for SIGALRM");
228 + if (out != NULL)
229 + return errno = EINVAL,
230 + error("sigaction: param 3 != NULL not implemented");
231 +
232 + timer_fn = in->sa_handler;
233 + return 0;
234 +}
235 +
236 +#undef signal
237 +sig_handler_t mingw_signal(int sig, sig_handler_t handler)
238 +{
239 + if (sig != SIGALRM)
240 + return signal(sig, handler);
241 + sig_handler_t old = timer_fn;
242 + timer_fn = handler;
243 + return old;
244 }
compat/mingw.h
+3
@@ -154,6 +154,9 @@ char *mingw_getcwd(char *pointer, int len);
154 int mingw_rename(const char*, const char*);
155 #define rename mingw_rename
156
157 +sig_handler_t mingw_signal(int sig, sig_handler_t handler);
158 +#define signal mingw_signal
159 +
160 /*
161 * git specific compatibility
162 */