diff options
Diffstat (limited to 'win32')
-rw-r--r-- | win32/mingw.c | 124 |
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 | |||
94 | static HANDLE timer_event; | ||
95 | static HANDLE timer_thread; | ||
96 | static int timer_interval; | ||
97 | static int one_shot; | ||
98 | static 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 | |||
109 | static __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 | |||
122 | static 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 | |||
138 | static 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 | |||
157 | static 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 | |||
162 | int 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 | |||
193 | int 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 | ||
209 | sighandler_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 | } | ||