aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-04-14 06:58:30 +0200
committerNguyễn Thái Ngọc Duy <pclouds@gmail.com>2010-09-10 18:40:06 +1000
commit69f49ea0d70939340e8a2c28aae36c8e2f3fb41e (patch)
tree75bb11ec769cd3529084b1da755d97c09a2545d5
parent9f4e87b2e7c18243341707a2d2df3957105139e5 (diff)
downloadbusybox-w32-69f49ea0d70939340e8a2c28aae36c8e2f3fb41e.tar.gz
busybox-w32-69f49ea0d70939340e8a2c28aae36c8e2f3fb41e.tar.bz2
busybox-w32-69f49ea0d70939340e8a2c28aae36c8e2f3fb41e.zip
win32: add signal routines and SIGALRM support
The implementation for SIGALRM only because Git needs it (I think for progress display or something). Probably not hurt having it. Although the only thing needed here are stubs.
-rw-r--r--include/mingw.h4
-rw-r--r--win32/mingw.c124
2 files changed, 127 insertions, 1 deletions
diff --git a/include/mingw.h b/include/mingw.h
index c5f72837b..0ff7f5442 100644
--- a/include/mingw.h
+++ b/include/mingw.h
@@ -109,9 +109,11 @@ struct sigaction {
109#define sigemptyset(x) (void)0 109#define sigemptyset(x) (void)0
110#define SA_RESTART 0 110#define SA_RESTART 0
111 111
112NOIMPL(sigaction,int sig UNUSED_PARAM, struct sigaction *in UNUSED_PARAM, struct sigaction *out UNUSED_PARAM); 112int sigaction(int sig, struct sigaction *in, struct sigaction *out);
113sighandler_t mingw_signal(int sig, sighandler_t handler);
113NOIMPL(sigfillset,int *mask UNUSED_PARAM); 114NOIMPL(sigfillset,int *mask UNUSED_PARAM);
114 115
116#define signal mingw_signal
115/* 117/*
116 * stdio.h 118 * stdio.h
117 */ 119 */
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}