aboutsummaryrefslogtreecommitdiff
path: root/win32
diff options
context:
space:
mode:
Diffstat (limited to 'win32')
-rw-r--r--win32/mingw.c124
1 files changed, 124 insertions, 0 deletions
diff --git a/win32/mingw.c b/win32/mingw.c
index 2b9776175..72e23998c 100644
--- a/win32/mingw.c
+++ b/win32/mingw.c
@@ -90,3 +90,127 @@ struct passwd *getpwuid(int uid)
90 p.pw_dir = NULL; 90 p.pw_dir = NULL;
91 return &p; 91 return &p;
92} 92}
93
94static HANDLE timer_event;
95static HANDLE timer_thread;
96static int timer_interval;
97static int one_shot;
98static sighandler_t timer_fn = SIG_DFL;
99
100/* The timer works like this:
101 * The thread, ticktack(), is a trivial routine that most of the time
102 * only waits to receive the signal to terminate. The main thread tells
103 * the thread to terminate by setting the timer_event to the signalled
104 * state.
105 * But ticktack() interrupts the wait state after the timer's interval
106 * length to call the signal handler.
107 */
108
109static __stdcall unsigned ticktack(void *dummy UNUSED_PARAM)
110{
111 while (WaitForSingleObject(timer_event, timer_interval) == WAIT_TIMEOUT) {
112 if (timer_fn == SIG_DFL)
113 bb_error_msg_and_die("Alarm");
114 if (timer_fn != SIG_IGN)
115 timer_fn(SIGALRM);
116 if (one_shot)
117 break;
118 }
119 return 0;
120}
121
122static int start_timer_thread(void)
123{
124 timer_event = CreateEvent(NULL, FALSE, FALSE, NULL);
125 if (timer_event) {
126 timer_thread = (HANDLE) _beginthreadex(NULL, 0, ticktack, NULL, 0, NULL);
127 if (!timer_thread ) {
128 errno = ENOMEM;
129 return -1;
130 }
131 } else {
132 errno = ENOMEM;
133 return -1;
134 }
135 return 0;
136}
137
138static void stop_timer_thread(void)
139{
140 if (timer_event)
141 SetEvent(timer_event); /* tell thread to terminate */
142 if (timer_thread) {
143 int rc = WaitForSingleObject(timer_thread, 1000);
144 if (rc == WAIT_TIMEOUT)
145 fprintf(stderr, "timer thread did not terminate timely");
146 else if (rc != WAIT_OBJECT_0)
147 fprintf(stderr, "waiting for timer thread failed: %lu",
148 GetLastError());
149 CloseHandle(timer_thread);
150 }
151 if (timer_event)
152 CloseHandle(timer_event);
153 timer_event = NULL;
154 timer_thread = NULL;
155}
156
157static inline int is_timeval_eq(const struct timeval *i1, const struct timeval *i2)
158{
159 return i1->tv_sec == i2->tv_sec && i1->tv_usec == i2->tv_usec;
160}
161
162int setitimer(int type UNUSED_PARAM, struct itimerval *in, struct itimerval *out)
163{
164 static const struct timeval zero;
165 static int atexit_done;
166
167 if (out != NULL) {
168 errno = EINVAL;
169 return -1;
170 }
171 if (!is_timeval_eq(&in->it_interval, &zero) &&
172 !is_timeval_eq(&in->it_interval, &in->it_value)) {
173 errno = EINVAL;
174 return -1;
175 }
176
177 if (timer_thread)
178 stop_timer_thread();
179
180 if (is_timeval_eq(&in->it_value, &zero) &&
181 is_timeval_eq(&in->it_interval, &zero))
182 return 0;
183
184 timer_interval = in->it_value.tv_sec * 1000 + in->it_value.tv_usec / 1000;
185 one_shot = is_timeval_eq(&in->it_interval, &zero);
186 if (!atexit_done) {
187 atexit(stop_timer_thread);
188 atexit_done = 1;
189 }
190 return start_timer_thread();
191}
192
193int sigaction(int sig, struct sigaction *in, struct sigaction *out)
194{
195 if (sig != SIGALRM) {
196 errno = EINVAL;
197 return -1;
198 }
199 if (out != NULL) {
200 errno = EINVAL;
201 return -1;
202 }
203
204 timer_fn = in->sa_handler;
205 return 0;
206}
207
208#undef signal
209sighandler_t mingw_signal(int sig, sighandler_t handler)
210{
211 sighandler_t old = timer_fn;
212 if (sig != SIGALRM)
213 return signal(sig, handler);
214 timer_fn = handler;
215 return old;
216}