diff options
author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-04-14 06:58:30 +0200 |
---|---|---|
committer | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-09-10 18:40:06 +1000 |
commit | 69f49ea0d70939340e8a2c28aae36c8e2f3fb41e (patch) | |
tree | 75bb11ec769cd3529084b1da755d97c09a2545d5 /win32 | |
parent | 9f4e87b2e7c18243341707a2d2df3957105139e5 (diff) | |
download | busybox-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.
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 | } | ||