aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorEli Zaretskii2012-09-30 17:49:05 +0200
committerEli Zaretskii2012-09-30 17:49:05 +0200
commitc06c382ae494c4129da43f2c1ea0f72e39a45bf1 (patch)
tree653f7b01aa6f0d91495440a111e8198273aa28e6 /src
parent8223b1d23361b74ede10bac47974ce7803804380 (diff)
downloademacs-c06c382ae494c4129da43f2c1ea0f72e39a45bf1.tar.gz
emacs-c06c382ae494c4129da43f2c1ea0f72e39a45bf1.zip
Support atimers and CPU profiler via profile.c on MS-Windows.
src/w32proc.c (sig_mask, crit_sig): New static variables. (sys_signal): Support SIGALRM and SIGPROF. (sigemptyset, sigaddset, sigfillset, sigprocmask) (pthread_sigmask, setpgrp): Moved here from w32.c. sigaddset, sigfillset, and sigprocmask are no longer no-ops. (sigismember): New function. (struct itimer_data): New definition. (ticks_now, real_itimer, prof_itimer, clocks_min, crit_real) (crit_prof): New static variables. (MAX_SINGLE_SLEEP): New definition. (timer_loop, stop_timer_thread, term_timers, init_timers) (start_timer_thread, getitimer, setitimer): New functions. (alarm): No longer a no-op, calls setitimer. src/w32.c (term_ntproc): Call term_timers. (init_ntproc): Make sure all signals are unblocked at startup, to erase any traces of dumping. Call init_timers. src/w32fns.c (hourglass_timer, HOURGLASS_ID): Remove. Windows-specific code to display the hourglass mouse pointer is no longer used. (w32_wnd_proc): Remove code that handled the WM_TIMER message due to hourglass timer expiration. (start_hourglass, cancel_hourglass, DEFAULT_HOURGLASS_DELAY): Remove, no longer used. (w32_note_current_window, show_hourglass, hide_hourglass): New functions, in support of hourglass cursor display similar to other window systems. (syms_of_w32fns): Don't initialize hourglass_timer. src/xdisp.c (start_hourglass, cancel_hourglass): Now used on WINDOWSNT as well. (start_hourglass) [WINDOWSNT]: Call w32_note_current_window. src/w32.h (init_timers, term_timers): Add prototypes. nt/inc/sys/time.h (ITIMER_REAL, ITIMER_PROF): Define. (struct itimerval): Define. (getitimer, setitimer): Add prototypes. nt/inc/ms-w32.h <sigset_t> [_MSVC_VER]: Make the typedef consistent with MinGW. (SA_RESTART, SIGPROF): Define. nt/config.nt (HAVE_SETITIMER): Define to 1.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog39
-rw-r--r--src/profiler.c2
-rw-r--r--src/w32.c58
-rw-r--r--src/w32.h3
-rw-r--r--src/w32fns.c83
-rw-r--r--src/w32proc.c532
-rw-r--r--src/xdisp.c9
7 files changed, 612 insertions, 114 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index 1f5ad1e6d05..504f8cbaed3 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,42 @@
12012-09-30 Eli Zaretskii <eliz@gnu.org>
2
3 Support atimers and CPU profiler via profile.c on MS-Windows.
4 * w32proc.c (sig_mask, crit_sig): New static variables.
5 (sys_signal): Support SIGALRM and SIGPROF.
6 (sigemptyset, sigaddset, sigfillset, sigprocmask)
7 (pthread_sigmask, setpgrp): Moved here from w32.c. sigaddset,
8 sigfillset, and sigprocmask are no longer no-ops.
9 (sigismember): New function.
10 (struct itimer_data): New definition.
11 (ticks_now, real_itimer, prof_itimer, clocks_min, crit_real)
12 (crit_prof): New static variables.
13 (MAX_SINGLE_SLEEP): New definition.
14 (timer_loop, stop_timer_thread, term_timers, init_timers)
15 (start_timer_thread, getitimer, setitimer): New functions.
16 (alarm): No longer a no-op, calls setitimer.
17
18 * w32.c (term_ntproc): Call term_timers.
19 (init_ntproc): Make sure all signals are unblocked at startup, to
20 erase any traces of dumping. Call init_timers.
21
22 * w32fns.c (hourglass_timer, HOURGLASS_ID): Remove.
23 Windows-specific code to display the hourglass mouse pointer is no
24 longer used.
25 (w32_wnd_proc): Remove code that handled the WM_TIMER message due
26 to hourglass timer expiration.
27 (start_hourglass, cancel_hourglass, DEFAULT_HOURGLASS_DELAY):
28 Remove, no longer used.
29 (w32_note_current_window, show_hourglass, hide_hourglass): New
30 functions, in support of hourglass cursor display similar to other
31 window systems.
32 (syms_of_w32fns): Don't initialize hourglass_timer.
33
34 * xdisp.c (start_hourglass, cancel_hourglass): Now used on
35 WINDOWSNT as well.
36 (start_hourglass) [WINDOWSNT]: Call w32_note_current_window.
37
38 * w32.h (init_timers, term_timers): Add prototypes.
39
12012-09-30 Kenichi Handa <handa@gnu.org> 402012-09-30 Kenichi Handa <handa@gnu.org>
2 41
3 * coding.c (decode_coding_ccl, encode_coding_ccl): Pay attention 42 * coding.c (decode_coding_ccl, encode_coding_ccl): Pay attention
diff --git a/src/profiler.c b/src/profiler.c
index 90a85c5230e..de118d13859 100644
--- a/src/profiler.c
+++ b/src/profiler.c
@@ -200,8 +200,6 @@ record_backtrace (log_t *log, EMACS_INT count)
200 200
201/* Sample profiler. */ 201/* Sample profiler. */
202 202
203/* FIXME: Add support for the CPU profiler in W32. */
204
205#ifdef PROFILER_CPU_SUPPORT 203#ifdef PROFILER_CPU_SUPPORT
206 204
207/* The profiler timer and whether it was properly initialized, if 205/* The profiler timer and whether it was properly initialized, if
diff --git a/src/w32.c b/src/w32.c
index 3154c725abf..7977e979b13 100644
--- a/src/w32.c
+++ b/src/w32.c
@@ -1528,52 +1528,6 @@ is_unc_volume (const char *filename)
1528 return 1; 1528 return 1;
1529} 1529}
1530 1530
1531/* Routines that are no-ops on NT but are defined to get Emacs to compile. */
1532int
1533sigemptyset (sigset_t *set)
1534{
1535 *set = 0;
1536 return 0;
1537}
1538
1539int
1540sigaddset (sigset_t *set, int signo)
1541{
1542 return 0;
1543}
1544
1545int
1546sigfillset (sigset_t *set)
1547{
1548 return 0;
1549}
1550
1551int
1552sigprocmask (int how, const sigset_t *set, sigset_t *oset)
1553{
1554 return 0;
1555}
1556
1557int
1558pthread_sigmask (int how, const sigset_t *set, sigset_t *oset)
1559{
1560 if (sigprocmask (how, set, oset) == -1)
1561 return EINVAL;
1562 return 0;
1563}
1564
1565int
1566setpgrp (int pid, int gid)
1567{
1568 return 0;
1569}
1570
1571int
1572alarm (int seconds)
1573{
1574 return 0;
1575}
1576
1577#define REG_ROOT "SOFTWARE\\GNU\\Emacs" 1531#define REG_ROOT "SOFTWARE\\GNU\\Emacs"
1578 1532
1579LPBYTE 1533LPBYTE
@@ -6623,6 +6577,9 @@ void
6623term_ntproc (int ignored) 6577term_ntproc (int ignored)
6624{ 6578{
6625 (void)ignored; 6579 (void)ignored;
6580
6581 term_timers ();
6582
6626 /* shutdown the socket interface if necessary */ 6583 /* shutdown the socket interface if necessary */
6627 term_winsock (); 6584 term_winsock ();
6628 6585
@@ -6632,6 +6589,8 @@ term_ntproc (int ignored)
6632void 6589void
6633init_ntproc (int dumping) 6590init_ntproc (int dumping)
6634{ 6591{
6592 sigset_t initial_mask = 0;
6593
6635 /* Initialize the socket interface now if available and requested by 6594 /* Initialize the socket interface now if available and requested by
6636 the user by defining PRELOAD_WINSOCK; otherwise loading will be 6595 the user by defining PRELOAD_WINSOCK; otherwise loading will be
6637 delayed until open-network-stream is called (w32-has-winsock can 6596 delayed until open-network-stream is called (w32-has-winsock can
@@ -6708,7 +6667,12 @@ init_ntproc (int dumping)
6708 /* unfortunately, atexit depends on implementation of malloc */ 6667 /* unfortunately, atexit depends on implementation of malloc */
6709 /* atexit (term_ntproc); */ 6668 /* atexit (term_ntproc); */
6710 if (!dumping) 6669 if (!dumping)
6711 signal (SIGABRT, term_ntproc); 6670 {
6671 /* Make sure we start with all signals unblocked. */
6672 sigprocmask (SIG_SETMASK, &initial_mask, NULL);
6673 signal (SIGABRT, term_ntproc);
6674 }
6675 init_timers ();
6712 6676
6713 /* determine which drives are fixed, for GetCachedVolumeInformation */ 6677 /* determine which drives are fixed, for GetCachedVolumeInformation */
6714 { 6678 {
diff --git a/src/w32.h b/src/w32.h
index a833c8f4315..2e2315e245d 100644
--- a/src/w32.h
+++ b/src/w32.h
@@ -142,6 +142,9 @@ extern void syms_of_fontset (void);
142extern void syms_of_w32font (void); 142extern void syms_of_w32font (void);
143extern void check_windows_init_file (void); 143extern void check_windows_init_file (void);
144 144
145extern void term_timers (void);
146extern void init_timers (void);
147
145extern int _sys_read_ahead (int fd); 148extern int _sys_read_ahead (int fd);
146extern int _sys_wait_accept (int fd); 149extern int _sys_wait_accept (int fd);
147 150
diff --git a/src/w32fns.c b/src/w32fns.c
index d7b45e263b3..b857e450476 100644
--- a/src/w32fns.c
+++ b/src/w32fns.c
@@ -79,9 +79,7 @@ extern void w32_menu_display_help (HWND, HMENU, UINT, UINT);
79extern void w32_free_menu_strings (HWND); 79extern void w32_free_menu_strings (HWND);
80extern const char *map_w32_filename (const char *, const char **); 80extern const char *map_w32_filename (const char *, const char **);
81 81
82/* If non-zero, a w32 timer that, when it expires, displays an 82/* If non-NULL, a handle to a frame where to display the hourglass cursor. */
83 hourglass cursor on all frames. */
84static unsigned hourglass_timer = 0;
85static HWND hourglass_hwnd = NULL; 83static HWND hourglass_hwnd = NULL;
86 84
87#ifndef IDC_HAND 85#ifndef IDC_HAND
@@ -175,7 +173,6 @@ unsigned int msh_mousewheel = 0;
175#define MOUSE_BUTTON_ID 1 173#define MOUSE_BUTTON_ID 1
176#define MOUSE_MOVE_ID 2 174#define MOUSE_MOVE_ID 2
177#define MENU_FREE_ID 3 175#define MENU_FREE_ID 3
178#define HOURGLASS_ID 4
179/* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP 176/* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP
180 is received. */ 177 is received. */
181#define MENU_FREE_DELAY 1000 178#define MENU_FREE_DELAY 1000
@@ -3313,12 +3310,6 @@ w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
3313 menubar_in_use = 0; 3310 menubar_in_use = 0;
3314 } 3311 }
3315 } 3312 }
3316 else if (wParam == hourglass_timer)
3317 {
3318 KillTimer (hwnd, hourglass_timer);
3319 hourglass_timer = 0;
3320 w32_show_hourglass (x_window_to_frame (dpyinfo, hwnd));
3321 }
3322 return 0; 3313 return 0;
3323 3314
3324 case WM_NCACTIVATE: 3315 case WM_NCACTIVATE:
@@ -5040,66 +5031,50 @@ no value of TYPE (always string in the MS Windows case). */)
5040 Busy cursor 5031 Busy cursor
5041 ***********************************************************************/ 5032 ***********************************************************************/
5042 5033
5043/* Default number of seconds to wait before displaying an hourglass
5044 cursor. Duplicated from xdisp.c, but cannot use the version there
5045 due to lack of atimers on w32. */
5046#define DEFAULT_HOURGLASS_DELAY 1
5047
5048/* Cancel a currently active hourglass timer, and start a new one. */
5049
5050void 5034void
5051start_hourglass (void) 5035w32_note_current_window (void)
5052{ 5036{
5053 DWORD delay;
5054 int secs, msecs = 0;
5055 struct frame * f = SELECTED_FRAME (); 5037 struct frame * f = SELECTED_FRAME ();
5056 5038
5057 /* No cursors on non GUI frames. */
5058 if (!FRAME_W32_P (f)) 5039 if (!FRAME_W32_P (f))
5059 return; 5040 return;
5060 5041
5061 cancel_hourglass ();
5062
5063 if (INTEGERP (Vhourglass_delay)
5064 && XINT (Vhourglass_delay) > 0)
5065 secs = XFASTINT (Vhourglass_delay);
5066 else if (FLOATP (Vhourglass_delay)
5067 && XFLOAT_DATA (Vhourglass_delay) > 0)
5068 {
5069 Lisp_Object tem;
5070 tem = Ftruncate (Vhourglass_delay, Qnil);
5071 secs = XFASTINT (tem);
5072 msecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000;
5073 }
5074 else
5075 secs = DEFAULT_HOURGLASS_DELAY;
5076
5077 delay = secs * 1000 + msecs;
5078 hourglass_hwnd = FRAME_W32_WINDOW (f); 5042 hourglass_hwnd = FRAME_W32_WINDOW (f);
5079 hourglass_timer = SetTimer (hourglass_hwnd, HOURGLASS_ID, delay, NULL);
5080} 5043}
5081 5044
5082
5083/* Cancel the hourglass cursor timer if active, hide an hourglass
5084 cursor if shown. */
5085
5086void 5045void
5087cancel_hourglass (void) 5046show_hourglass (struct atimer *timer)
5088{ 5047{
5089 if (hourglass_timer) 5048 struct frame *f;
5090 {
5091 KillTimer (hourglass_hwnd, hourglass_timer);
5092 hourglass_timer = 0;
5093 }
5094 5049
5095 if (hourglass_shown_p) 5050 hourglass_atimer = NULL;
5096 w32_hide_hourglass (); 5051
5052 block_input ();
5053 f = x_window_to_frame (&one_w32_display_info,
5054 hourglass_hwnd);
5055
5056 if (f)
5057 f->output_data.w32->hourglass_p = 0;
5058 else
5059 f = SELECTED_FRAME ();
5060
5061 if (!FRAME_W32_P (f))
5062 return;
5063
5064 w32_show_hourglass (f);
5065 unblock_input ();
5097} 5066}
5098 5067
5068void
5069hide_hourglass (void)
5070{
5071 block_input ();
5072 w32_hide_hourglass ();
5073 unblock_input ();
5074}
5099 5075
5100/* Timer function of hourglass_timer.
5101 5076
5102 Display an hourglass cursor. Set the hourglass_p flag in display info 5077/* Display an hourglass cursor. Set the hourglass_p flag in display info
5103 to indicate that an hourglass cursor is shown. */ 5078 to indicate that an hourglass cursor is shown. */
5104 5079
5105static void 5080static void
@@ -7123,8 +7098,6 @@ only be necessary if the default setting causes problems. */);
7123 7098
7124 check_window_system_func = check_w32; 7099 check_window_system_func = check_w32;
7125 7100
7126
7127 hourglass_timer = 0;
7128 hourglass_hwnd = NULL; 7101 hourglass_hwnd = NULL;
7129 7102
7130 defsubr (&Sx_show_tip); 7103 defsubr (&Sx_show_tip);
diff --git a/src/w32proc.c b/src/w32proc.c
index b367b42d8c6..d7c9edac746 100644
--- a/src/w32proc.c
+++ b/src/w32proc.c
@@ -86,18 +86,23 @@ typedef void (_CALLBACK_ *signal_handler) (int);
86/* Signal handlers...SIG_DFL == 0 so this is initialized correctly. */ 86/* Signal handlers...SIG_DFL == 0 so this is initialized correctly. */
87static signal_handler sig_handlers[NSIG]; 87static signal_handler sig_handlers[NSIG];
88 88
89static sigset_t sig_mask;
90
91static CRITICAL_SECTION crit_sig;
92
89/* Improve on the CRT 'signal' implementation so that we could record 93/* Improve on the CRT 'signal' implementation so that we could record
90 the SIGCHLD handler. */ 94 the SIGCHLD handler and fake interval timers. */
91signal_handler 95signal_handler
92sys_signal (int sig, signal_handler handler) 96sys_signal (int sig, signal_handler handler)
93{ 97{
94 signal_handler old; 98 signal_handler old;
95 99
96 /* SIGCHLD is needed for supporting subprocesses, see sys_kill 100 /* SIGCHLD is needed for supporting subprocesses, see sys_kill
97 below. All the others are the only ones supported by the MS 101 below. SIGALRM and SIGPROF are used by setitimer. All the
98 runtime. */ 102 others are the only ones supported by the MS runtime. */
99 if (!(sig == SIGCHLD || sig == SIGSEGV || sig == SIGILL 103 if (!(sig == SIGCHLD || sig == SIGSEGV || sig == SIGILL
100 || sig == SIGFPE || sig == SIGABRT || sig == SIGTERM)) 104 || sig == SIGFPE || sig == SIGABRT || sig == SIGTERM
105 || sig == SIGALRM || sig == SIGPROF))
101 { 106 {
102 errno = EINVAL; 107 errno = EINVAL;
103 return SIG_ERR; 108 return SIG_ERR;
@@ -111,7 +116,7 @@ sys_signal (int sig, signal_handler handler)
111 if (!(sig == SIGABRT && old == term_ntproc)) 116 if (!(sig == SIGABRT && old == term_ntproc))
112 { 117 {
113 sig_handlers[sig] = handler; 118 sig_handlers[sig] = handler;
114 if (sig != SIGCHLD) 119 if (!(sig == SIGCHLD || sig == SIGALRM || sig == SIGPROF))
115 signal (sig, handler); 120 signal (sig, handler);
116 } 121 }
117 return old; 122 return old;
@@ -143,6 +148,523 @@ sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
143 return retval; 148 return retval;
144} 149}
145 150
151/* Emulate signal sets and blocking of signals used by timers. */
152
153int
154sigemptyset (sigset_t *set)
155{
156 *set = 0;
157 return 0;
158}
159
160int
161sigaddset (sigset_t *set, int signo)
162{
163 if (!set)
164 {
165 errno = EINVAL;
166 return -1;
167 }
168 if (signo < 0 || signo >= NSIG)
169 {
170 errno = EINVAL;
171 return -1;
172 }
173
174 *set |= (1U << signo);
175
176 return 0;
177}
178
179int
180sigfillset (sigset_t *set)
181{
182 if (!set)
183 {
184 errno = EINVAL;
185 return -1;
186 }
187
188 *set = 0xFFFFFFFF;
189 return 0;
190}
191
192int
193sigprocmask (int how, const sigset_t *set, sigset_t *oset)
194{
195 if (!(how == SIG_BLOCK || how == SIG_UNBLOCK || how == SIG_SETMASK))
196 {
197 errno = EINVAL;
198 return -1;
199 }
200
201 if (oset)
202 *oset = sig_mask;
203
204 if (!set)
205 return 0;
206
207 switch (how)
208 {
209 case SIG_BLOCK:
210 sig_mask |= *set;
211 break;
212 case SIG_SETMASK:
213 sig_mask = *set;
214 break;
215 case SIG_UNBLOCK:
216 /* FIXME: Catch signals that are blocked and reissue them when
217 they are unblocked. Important for SIGALRM and SIGPROF only. */
218 sig_mask &= ~(*set);
219 break;
220 }
221
222 return 0;
223}
224
225int
226pthread_sigmask (int how, const sigset_t *set, sigset_t *oset)
227{
228 if (sigprocmask (how, set, oset) == -1)
229 return EINVAL;
230 return 0;
231}
232
233int
234sigismember (const sigset_t *set, int signo)
235{
236 if (signo < 0 || signo >= NSIG)
237 {
238 errno = EINVAL;
239 return -1;
240 }
241 if (signo > sizeof (*set) * BITS_PER_CHAR)
242 emacs_abort ();
243
244 return (*set & (1U << signo)) != 0;
245}
246
247int
248setpgrp (int pid, int gid)
249{
250 return 0;
251}
252
253/* Emulations of interval timers.
254
255 Limitations: only ITIMER_REAL and ITIMER_PROF are supported.
256
257 Implementation: a separate thread is started for each timer type,
258 the thread calls the appropriate signal handler when the timer
259 expires, after stopping the thread which installed the timer. */
260
261/* FIXME: clock_t counts overflow after 49 days, need to handle the
262 wrap-around. */
263struct itimer_data {
264 clock_t expire;
265 clock_t reload;
266 int terminate;
267 int type;
268 HANDLE caller_thread;
269 HANDLE timer_thread;
270};
271
272static clock_t ticks_now;
273static struct itimer_data real_itimer, prof_itimer;
274static clock_t clocks_min;
275
276static CRITICAL_SECTION crit_real, crit_prof;
277
278#define MAX_SINGLE_SLEEP 30
279
280static DWORD WINAPI
281timer_loop (LPVOID arg)
282{
283 struct itimer_data *itimer = (struct itimer_data *)arg;
284 int which = itimer->type;
285 int sig = (which == ITIMER_REAL) ? SIGALRM : SIGPROF;
286 CRITICAL_SECTION *crit = (which == ITIMER_REAL) ? &crit_real : &crit_prof;
287 const DWORD max_sleep = MAX_SINGLE_SLEEP * 1000 / CLOCKS_PER_SEC;
288 int new_count = 0;
289
290 while (1)
291 {
292 DWORD sleep_time;
293 signal_handler handler;
294 clock_t now, expire, reload;
295
296 /* Load new values if requested by setitimer. */
297 EnterCriticalSection (crit);
298 expire = itimer->expire;
299 reload = itimer->reload;
300 LeaveCriticalSection (crit);
301 if (itimer->terminate)
302 return 0;
303
304 if (itimer->expire == 0)
305 {
306 /* We are idle. */
307 Sleep (max_sleep);
308 continue;
309 }
310
311 expire = itimer->expire;
312 if (expire > (now = clock ()))
313 sleep_time = expire - now;
314 else
315 sleep_time = 0;
316 /* Don't sleep too long at a time, to be able to see the
317 termination flag without too long a delay. */
318 while (sleep_time > max_sleep)
319 {
320 if (itimer->terminate)
321 return 0;
322 Sleep (max_sleep);
323 expire = itimer->expire;
324 sleep_time = (expire > (now = clock ())) ? expire - now : 0;
325 }
326 if (itimer->terminate)
327 return 0;
328 if (sleep_time > 0)
329 {
330 Sleep (sleep_time * 1000 / CLOCKS_PER_SEC);
331 /* Always sleep past the expiration time, to make sure we
332 never call the handler _before_ the expiration time,
333 always slightly after it. Sleep(0) relinquishes the rest
334 of the scheduled slot, so that we let other threads
335 work. */
336 while (clock () < expire)
337 Sleep (0);
338 }
339
340 if (itimer->expire == 0)
341 continue;
342
343 /* Time's up. */
344 handler = sig_handlers[sig];
345 if (!(handler == SIG_DFL || handler == SIG_IGN || handler == SIG_ERR)
346 /* FIXME: Don't ignore masked signals. Instead, record that
347 they happened and reissue them when the signal is
348 unblocked. */
349 && !sigismember (&sig_mask, sig)
350 /* Simulate masking of SIGALRM and SIGPROF when processing
351 fatal signals. */
352 && !fatal_error_in_progress
353 && itimer->caller_thread)
354 {
355 /* Simulate a signal delivered to the thread which installed
356 the timer, by suspending that thread while the handler
357 runs. */
358 DWORD result = SuspendThread (itimer->caller_thread);
359
360 if (result == (DWORD)-1)
361 {
362 DebPrint (("Thread %d exiting with status 2\n", which));
363 return 2;
364 }
365 handler (sig);
366 ResumeThread (itimer->caller_thread);
367 }
368
369 if (itimer->expire == 0)
370 continue;
371
372 /* Update expiration time and loop. */
373 EnterCriticalSection (crit);
374 expire = itimer->expire;
375 reload = itimer->reload;
376 if (reload > 0)
377 {
378 now = clock ();
379 if (expire <= now)
380 {
381 clock_t lag = now - expire;
382
383 /* If we missed some opportunities (presumably while
384 sleeping or while the signal handler ran), skip
385 them. */
386 if (lag > reload)
387 expire = now - (lag % reload);
388
389 expire += reload;
390 }
391 }
392 else
393 expire = 0; /* become idle */
394 itimer->expire = expire;
395 LeaveCriticalSection (crit);
396 }
397 return 0;
398}
399
400static void
401stop_timer_thread (int which)
402{
403 struct itimer_data *itimer =
404 (which == ITIMER_REAL) ? &real_itimer : &prof_itimer;
405 int i;
406 DWORD exit_code = 255;
407 BOOL status, err;
408
409 /* Signal the thread that it should terminate. */
410 itimer->terminate = 1;
411
412 if (itimer->timer_thread == NULL)
413 return;
414
415 /* Wait for the timer thread to terminate voluntarily, then kill it
416 if it doesn't. This loop waits twice more than the maximum
417 amount of time a timer thread sleeps, see above. */
418 for (i = 0; i < MAX_SINGLE_SLEEP / 5; i++)
419 {
420 if (!((status = GetExitCodeThread (itimer->timer_thread, &exit_code))
421 && exit_code == STILL_ACTIVE))
422 break;
423 Sleep (10);
424 }
425 if ((status == FALSE && (err = GetLastError ()) == ERROR_INVALID_HANDLE)
426 || exit_code == STILL_ACTIVE)
427 {
428 if (!(status == FALSE && err == ERROR_INVALID_HANDLE))
429 TerminateThread (itimer->timer_thread, 0);
430 }
431
432 /* Clean up. */
433 CloseHandle (itimer->timer_thread);
434 itimer->timer_thread = NULL;
435 if (itimer->caller_thread)
436 {
437 CloseHandle (itimer->caller_thread);
438 itimer->caller_thread = NULL;
439 }
440}
441
442/* This is called at shutdown time from term_ntproc. */
443void
444term_timers (void)
445{
446 if (real_itimer.timer_thread)
447 stop_timer_thread (ITIMER_REAL);
448 if (prof_itimer.timer_thread)
449 stop_timer_thread (ITIMER_PROF);
450
451 DeleteCriticalSection (&crit_real);
452 DeleteCriticalSection (&crit_prof);
453 DeleteCriticalSection (&crit_sig);
454}
455
456/* This is called at initialization time from init_ntproc. */
457void
458init_timers (void)
459{
460 /* Make sure we start with zeroed out itimer structures, since
461 dumping may have left there traces of threads long dead. */
462 memset (&real_itimer, 0, sizeof real_itimer);
463 memset (&prof_itimer, 0, sizeof prof_itimer);
464
465 InitializeCriticalSection (&crit_real);
466 InitializeCriticalSection (&crit_prof);
467 InitializeCriticalSection (&crit_sig);
468}
469
470static int
471start_timer_thread (int which)
472{
473 DWORD exit_code;
474 struct itimer_data *itimer =
475 (which == ITIMER_REAL) ? &real_itimer : &prof_itimer;
476
477 if (itimer->timer_thread
478 && GetExitCodeThread (itimer->timer_thread, &exit_code)
479 && exit_code == STILL_ACTIVE)
480 return 0;
481
482 /* Start a new thread. */
483 if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
484 GetCurrentProcess (), &itimer->caller_thread, 0,
485 FALSE, DUPLICATE_SAME_ACCESS))
486 {
487 errno = ESRCH;
488 return -1;
489 }
490
491 itimer->terminate = 0;
492 itimer->type = which;
493 /* Request that no more than 64KB of stack be reserved for this
494 thread, to avoid reserving too much memory, which would get in
495 the way of threads we start to wait for subprocesses. See also
496 new_child below. */
497 itimer->timer_thread = CreateThread (NULL, 64 * 1024, timer_loop,
498 (void *)itimer, 0x00010000, NULL);
499
500 if (!itimer->timer_thread)
501 {
502 CloseHandle (itimer->caller_thread);
503 itimer->caller_thread = NULL;
504 errno = EAGAIN;
505 return -1;
506 }
507
508 /* This is needed to make sure that the timer thread running for
509 profiling gets CPU as soon as the Sleep call terminates. */
510 if (which == ITIMER_PROF)
511 SetThreadPriority (itimer->caller_thread, THREAD_PRIORITY_TIME_CRITICAL);
512
513 return 0;
514}
515
516/* Most of the code of getitimer and setitimer (but not of their
517 subroutines) was shamelessly stolen from itimer.c in the DJGPP
518 library, see www.delorie.com/djgpp. */
519int
520getitimer (int which, struct itimerval *value)
521{
522 volatile clock_t *t_expire;
523 volatile clock_t *t_reload;
524 clock_t expire, reload;
525 __int64 usecs;
526 CRITICAL_SECTION *crit;
527
528 ticks_now = clock ();
529
530 if (!value)
531 {
532 errno = EFAULT;
533 return -1;
534 }
535
536 if (which != ITIMER_REAL && which != ITIMER_PROF)
537 {
538 errno = EINVAL;
539 return -1;
540 }
541
542 t_expire = (which == ITIMER_REAL) ? &real_itimer.expire: &prof_itimer.expire;
543 t_reload = (which == ITIMER_REAL) ? &real_itimer.reload: &prof_itimer.reload;
544 crit = (which == ITIMER_REAL) ? &crit_real : &crit_prof;
545
546 EnterCriticalSection (crit);
547 reload = *t_reload;
548 expire = *t_expire;
549 LeaveCriticalSection (crit);
550
551 if (expire)
552 expire -= ticks_now;
553
554 value->it_value.tv_sec = expire / CLOCKS_PER_SEC;
555 usecs = (expire % CLOCKS_PER_SEC) * (__int64)1000000 / CLOCKS_PER_SEC;
556 value->it_value.tv_usec = usecs;
557 value->it_interval.tv_sec = reload / CLOCKS_PER_SEC;
558 usecs = (reload % CLOCKS_PER_SEC) * (__int64)1000000 / CLOCKS_PER_SEC;
559 value->it_interval.tv_usec= usecs;
560
561 return 0;
562}
563
564int
565setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
566{
567 volatile clock_t *t_expire, *t_reload;
568 clock_t expire, reload, expire_old, reload_old;
569 __int64 usecs;
570 CRITICAL_SECTION *crit;
571
572 /* Posix systems expect timer values smaller than the resolution of
573 the system clock be rounded up to the clock resolution. First
574 time we are called, measure the clock tick resolution. */
575 if (!clocks_min)
576 {
577 clock_t t1, t2;
578
579 for (t1 = clock (); (t2 = clock ()) == t1; )
580 ;
581 clocks_min = t2 - t1;
582 }
583
584 if (ovalue)
585 {
586 if (getitimer (which, ovalue)) /* also sets ticks_now */
587 return -1; /* errno already set */
588 }
589 else
590 ticks_now = clock ();
591
592 if (which != ITIMER_REAL && which != ITIMER_PROF)
593 {
594 errno = EINVAL;
595 return -1;
596 }
597
598 t_expire =
599 (which == ITIMER_REAL) ? &real_itimer.expire : &prof_itimer.expire;
600 t_reload =
601 (which == ITIMER_REAL) ? &real_itimer.reload : &prof_itimer.reload;
602
603 crit = (which == ITIMER_REAL) ? &crit_real : &crit_prof;
604
605 if (!value
606 || (value->it_value.tv_sec == 0 && value->it_value.tv_usec == 0))
607 {
608 EnterCriticalSection (crit);
609 /* Disable the timer. */
610 *t_expire = 0;
611 *t_reload = 0;
612 LeaveCriticalSection (crit);
613 return 0;
614 }
615
616 reload = value->it_interval.tv_sec * CLOCKS_PER_SEC;
617
618 usecs = value->it_interval.tv_usec;
619 if (value->it_interval.tv_sec == 0
620 && usecs && usecs * CLOCKS_PER_SEC < clocks_min * 1000000)
621 reload = clocks_min;
622 else
623 {
624 usecs *= CLOCKS_PER_SEC;
625 reload += usecs / 1000000;
626 }
627
628 expire = value->it_value.tv_sec * CLOCKS_PER_SEC;
629 usecs = value->it_value.tv_usec;
630 if (value->it_value.tv_sec == 0
631 && usecs * CLOCKS_PER_SEC < clocks_min * 1000000)
632 expire = clocks_min;
633 else
634 {
635 usecs *= CLOCKS_PER_SEC;
636 expire += usecs / 1000000;
637 }
638
639 expire += ticks_now;
640
641 EnterCriticalSection (crit);
642 expire_old = *t_expire;
643 reload_old = *t_reload;
644 if (!(expire == expire_old && reload == reload_old))
645 {
646 *t_reload = reload;
647 *t_expire = expire;
648 }
649 LeaveCriticalSection (crit);
650
651 return start_timer_thread (which);
652}
653
654int
655alarm (int seconds)
656{
657 struct itimerval new_values;
658
659 new_values.it_value.tv_sec = seconds;
660 new_values.it_value.tv_usec = 0;
661 new_values.it_interval.tv_sec = new_values.it_interval.tv_usec = 0;
662
663 setitimer (ITIMER_REAL, &new_values, NULL);
664
665 return seconds;
666}
667
146/* Defined in <process.h> which conflicts with the local copy */ 668/* Defined in <process.h> which conflicts with the local copy */
147#define _P_NOWAIT 1 669#define _P_NOWAIT 1
148 670
diff --git a/src/xdisp.c b/src/xdisp.c
index b23a06ff3d1..1d267bd7ded 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -29357,10 +29357,6 @@ init_xdisp (void)
29357 help_echo_showing_p = 0; 29357 help_echo_showing_p = 0;
29358} 29358}
29359 29359
29360/* Since w32 does not support atimers, it defines its own implementation of
29361 the following three functions in w32fns.c. */
29362#ifndef WINDOWSNT
29363
29364/* Platform-independent portion of hourglass implementation. */ 29360/* Platform-independent portion of hourglass implementation. */
29365 29361
29366/* Cancel a currently active hourglass timer, and start a new one. */ 29362/* Cancel a currently active hourglass timer, and start a new one. */
@@ -29383,6 +29379,10 @@ start_hourglass (void)
29383 else 29379 else
29384 delay = make_emacs_time (DEFAULT_HOURGLASS_DELAY, 0); 29380 delay = make_emacs_time (DEFAULT_HOURGLASS_DELAY, 0);
29385 29381
29382#ifdef WINDOWSNT
29383 w32_note_current_window ();
29384#endif
29385
29386 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay, 29386 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
29387 show_hourglass, NULL); 29387 show_hourglass, NULL);
29388#endif 29388#endif
@@ -29405,4 +29405,3 @@ cancel_hourglass (void)
29405 hide_hourglass (); 29405 hide_hourglass ();
29406#endif 29406#endif
29407} 29407}
29408#endif /* ! WINDOWSNT */