The R Project SVN R

Rev

Rev 45070 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4958 ripley 1
/*****************************************************************************
2
 *                                                                           *
3
 * DH_SIG.C                                                                  *
4
 *                                                                           *
5
 * Freely redistributable and modifiable.  Use at your own risk.             *
6
 *                                                                           *
7
 * Copyright 1994 The Downhill Project                                       *
8
 *                                                                           *
9
 *****************************************************************************/
10
 
8872 pd 11
#ifdef HAVE_CONFIG_H
12
#include <config.h>
13
#endif
14
 
36901 ripley 15
#define WIN32_LEAN_AND_MEAN 1
6283 guido 16
#include <windows.h>
4958 ripley 17
#include "psignal.h"
17349 ripley 18
extern int UserBreak;
4958 ripley 19
 
20
/* Define stuff ************************************************************ */
21
#ifndef TRUE
45070 ripley 22
# define TRUE 1
4958 ripley 23
#endif
24
#ifndef FALSE
45070 ripley 25
# define FALSE 0
4958 ripley 26
#endif
27
 
28
/* Signal groupings ======================================================== */
29
#define SIGNAL_DEFAULT_EXIT         case SIGABRT:               \
45070 ripley 30
				    case SIGFPE:                \
31
				    case SIGILL:                \
32
				    case SIGINT:                \
33
				    case SIGSEGV:               \
34
				    case SIGTERM:
4958 ripley 35
 
36
#define IS_SIGNAL(a)        ( ((a) > 0 ) &&  ((a) < NSIG))
37
 
38
 
39
/* Struct stuff **************************************************************/
40
struct downhill_Signal_Struct
41
{
45070 ripley 42
    void     (*signal_Handler)(int);
43
    int      signal_Count;
44
    int      signal_Extra;
45
    sigset_t signal_Mask;
46
    int      signal_Flags;
4958 ripley 47
};
48
 
49
 
50
/* Static stuff **************************************************************/
51
static struct downhill_Signal_Struct* downhill_Signal_Info = NULL;
52
static sigset_t                       downhill_Sigset_Mask = 0;
6283 guido 53
static HANDLE                            IGotASignal;
4958 ripley 54
 
55
/* Function stuff ************************************************************/
56
 
57
 
58
/* Handle a signal ========================================================= */
6283 guido 59
void raise(int signal_Number)
4958 ripley 60
{
45070 ripley 61
    if (!IS_SIGNAL(signal_Number)) {
62
	errno = EINVAL;
63
	return;
64
    }
65
    /* Check to see if we're masking this signal */
66
    if (sigismember(&downhill_Sigset_Mask,signal_Number))
67
    {
68
	downhill_Signal_Info[signal_Number].signal_Count++;
69
    }
70
    else
71
    {
72
	/* Do a signal's action */
73
	if (downhill_Signal_Info[signal_Number].signal_Handler ==
74
	    SIG_DFL)
4958 ripley 75
	{
45070 ripley 76
	    switch (signal_Number)
77
	    {
78
		SIGNAL_DEFAULT_EXIT
79
		    exit(3);
80
	    default:
81
		break;
82
	    }
4958 ripley 83
	}
45070 ripley 84
	else if (
84952 kalibera 85
	    downhill_Signal_Info[signal_Number].signal_Handler ==
86
	    SIG_IGN
45070 ripley 87
	    )
88
	{/* IGNORE */}
4958 ripley 89
	else
45070 ripley 90
	{
91
	    void (*signal_HandlerOld)(int);
92
	    /* Do we reset the handler? */
93
	    signal_HandlerOld =
94
		downhill_Signal_Info[signal_Number].signal_Handler;
95
	    if (downhill_Signal_Info[signal_Number].signal_Flags&
96
		SA_RESETHAND)
97
	    {
98
		downhill_Signal_Info[signal_Number].
99
		    signal_Handler = SIG_DFL;
100
	    }
101
	    /* Do the action */
102
	    if ((signal_Number == SIGCHLD) &&
103
		(downhill_Signal_Info[signal_Number].signal_Flags&
104
		 SA_NOCLDSTOP))
105
	    {
106
		/* Ignore SIGCHLD */
107
	    }
108
	    else
109
	    {
110
		sigset_t sigset_MaskOriginal =
111
		    downhill_Sigset_Mask;
112
		sigset_t sigset_MaskNew = downhill_Signal_Info[
113
		    signal_Number].signal_Mask;
4958 ripley 114
 
45070 ripley 115
		/* Set the new signal mask */
116
		sigaddset(&sigset_MaskNew,signal_Number);
117
		sigprocmask(SIG_BLOCK,&sigset_MaskNew,NULL);
4958 ripley 118
 
45070 ripley 119
		/* Execute the handler */
120
		signal_HandlerOld(signal_Number);
4958 ripley 121
 
45070 ripley 122
		/* Restore the signal mask */
123
		sigprocmask(SIG_SETMASK,&sigset_MaskOriginal,
124
			    NULL);
4958 ripley 125
 
45070 ripley 126
	    }
4958 ripley 127
	}
45070 ripley 128
	PulseEvent(IGotASignal);
129
    }
4958 ripley 130
}
131
 
132
/* Init the signal re-direction ============================================ */
6283 guido 133
 
134
/* Hardware interrupt handler.  */
135
static BOOL CALLBACK hwIntrHandler (DWORD type)
136
{
45070 ripley 137
    int ret;
138
    switch (type) {
139
    case CTRL_C_EVENT :
140
    case CTRL_BREAK_EVENT :
141
	/*
142
	  Why SIGBREAK? SIGINT is used internally by R and the signal
143
	  handler for SIGINT ends with a 'longjmp'. But, under Windows,
144
	  hardware interrupt handler runs in a different thread. So,
145
	  longjmp fails (tipically it will crash R). So, we raise a SIGBREAK
146
	  to record that the user want to stop. This is then
147
	  processed at due time. Drawback of this approach: if R is lost
148
	  inside a C or Fortran routine we don't break it. I (g.m.) have
149
	  tried to raise a signal in the appropriate thread using
150
	  SuspendThread/GetThreadContext/setting Eip to the signal handler/
151
	  SetThreadContext/ResumeThread but I had success only under NT.
152
	*/
153
	raise(SIGBREAK);
154
	/* Seems that SIGBREAK is not working under 1,4,0, so do it via
155
	   a semaphore, as RGui does */
156
	UserBreak = 1;
157
	ret = TRUE;
158
	break;
159
    default:
160
	ret = FALSE;
161
    }
162
    return ret ;
6283 guido 163
}
164
 
4958 ripley 165
static int downhill_Signal_Init(void)
166
{
45070 ripley 167
    /* Skip this if we've already done it */
168
    if (downhill_Signal_Info == NULL)
169
    {
170
	if (!(downhill_Signal_Info =
171
	      calloc(sizeof(struct downhill_Signal_Struct),NSIG)) ||
172
	    !(IGotASignal=CreateEvent(NULL,FALSE,FALSE,NULL)) ||
173
	    !SetConsoleCtrlHandler (hwIntrHandler, TRUE))
174
 
4958 ripley 175
	{
45070 ripley 176
	    if (downhill_Signal_Info) free(downhill_Signal_Info);
177
	    if (IGotASignal) CloseHandle(IGotASignal);
178
	    errno = ENOMEM;
179
	    return FALSE;
4958 ripley 180
	}
45070 ripley 181
    }
182
    return TRUE;
4958 ripley 183
}
184
 
185
/* Set a signal action ===================================================== */
186
int sigaction(int signal_Number,struct sigaction* sigaction_Info,
187
     struct sigaction* sigaction_InfoOld)
188
{
45070 ripley 189
    /* Make sure we're init'd */
190
    if (!downhill_Signal_Init())
191
    {
192
	return -1;
193
    }
194
 
195
    /* Set the signal */
196
    if (IS_SIGNAL(signal_Number)) {
197
	if (sigaction_InfoOld != NULL)
4958 ripley 198
	{
45070 ripley 199
	    sigaction_InfoOld->sa_handler =
200
		downhill_Signal_Info[signal_Number].
201
		signal_Handler;
202
	    sigaction_InfoOld->sa_mask =
203
		downhill_Signal_Info[signal_Number].
204
		signal_Mask;
205
	    sigaction_InfoOld->sa_flags =
206
		downhill_Signal_Info[signal_Number].
207
		signal_Flags;
4958 ripley 208
	}
45070 ripley 209
	if (sigaction_Info != NULL)
210
	{
211
	    downhill_Signal_Info[signal_Number].
212
		signal_Handler = sigaction_Info->sa_handler;
213
	    downhill_Signal_Info[signal_Number].
214
		signal_Count = 0;
215
	    downhill_Signal_Info[signal_Number].
216
		signal_Extra = 0;
217
	    downhill_Signal_Info[signal_Number].
218
		signal_Mask = sigaction_Info->sa_mask;
219
	    downhill_Signal_Info[signal_Number].
220
		signal_Flags = sigaction_Info->sa_flags;
4958 ripley 221
	}
45070 ripley 222
    }
223
    else  {
224
	errno = EINVAL;
225
	return -1;
226
    }
4958 ripley 227
 
45070 ripley 228
    return 0;
4958 ripley 229
}
230
 
231
/* Set the action of a signal ============================================== */
6283 guido 232
sighandler_t signal(int signal_Number, sighandler_t signal_Handler)
4958 ripley 233
{
45070 ripley 234
    sighandler_t signal_HandlerOld;
4958 ripley 235
 
45070 ripley 236
    /* Make sure we're init'd */
237
    if (!IS_SIGNAL(signal_Number) || !downhill_Signal_Init() )
238
    {
239
	return SIG_ERR;
240
    }
241
    signal_HandlerOld =
242
	downhill_Signal_Info[signal_Number].signal_Handler;
243
    downhill_Signal_Info[signal_Number].signal_Handler =
244
	signal_Handler;
245
    downhill_Signal_Info[signal_Number].signal_Count = 0;
246
    downhill_Signal_Info[signal_Number].signal_Extra = 0;
247
    downhill_Signal_Info[signal_Number].signal_Mask = 0;
248
    downhill_Signal_Info[signal_Number].signal_Flags = 0;
249
    return signal_HandlerOld;
4958 ripley 250
}
251
 
252
/* Add a signal to a set =================================================== */
253
int sigaddset(sigset_t* sigset_Info,int signal_Number)
254
{
255
    if (IS_SIGNAL(signal_Number)) {
45070 ripley 256
	(*sigset_Info) |= (1 << (signal_Number - 1));
257
	return 0;
4958 ripley 258
    }
259
    else {
45070 ripley 260
	errno = EINVAL;
261
	return -1;
4958 ripley 262
    }
263
    return 0;
264
}
265
 
266
/* Remove a signal from a set ============================================== */
267
int sigdelset(sigset_t* sigset_Info,int signal_Number)
268
{
269
    if (IS_SIGNAL(signal_Number)) {
45070 ripley 270
	*sigset_Info &= ~(1<< (signal_Number - 1));
271
	return 0;
4958 ripley 272
    }
273
    else {
45070 ripley 274
	errno = EINVAL;
275
	return -1;
4958 ripley 276
    }
277
    return 0;
278
}
279
 
280
/* Empty a set ============================================================= */
281
int sigemptyset(sigset_t* sigset_Info)
282
{
45070 ripley 283
    *sigset_Info = 0;
284
    return 0;
4958 ripley 285
}
286
 
287
/* Fill a set ============================================================== */
288
int sigfillset(sigset_t* sigset_Info)
289
{
45070 ripley 290
    *sigset_Info = (sigset_t)-1;
291
    return 0;
4958 ripley 292
}
293
 
294
/* Checks if a signal is in a set ========================================== */
295
int sigismember(sigset_t* sigset_Info,int signal_Number)
296
{
45070 ripley 297
    if (IS_SIGNAL(signal_Number)) {
298
	if ( *sigset_Info & (1 << (signal_Number-1)))
299
	    return 1;
300
	else
301
	    return 0;
302
    }
303
    errno = EINVAL;
304
    return -1;
4958 ripley 305
}
306
 
307
/* Returns the signals pending ============================================= */
308
int sigpending(sigset_t* sigset_Info)
309
{
45070 ripley 310
    int signal_Index;
311
    /* Make sure we're init'd */
312
    if (!downhill_Signal_Init())
313
    {
314
	return -1;
315
    }
316
    /* Check all the pending signals */
317
    sigemptyset(sigset_Info);
318
    for (signal_Index = 1;signal_Index < NSIG;signal_Index++)
319
    {
320
	if (downhill_Signal_Info[signal_Index].signal_Count > 0)
4958 ripley 321
	{
45070 ripley 322
	    sigaddset(sigset_Info,signal_Index);
4958 ripley 323
	}
45070 ripley 324
    }
4958 ripley 325
 
45070 ripley 326
    return 0;
4958 ripley 327
}
328
 
329
/* Change the blocked signals ============================================== */
330
int sigprocmask(int mask_Function,sigset_t* sigset_Info,
331
     sigset_t* sigset_InfoOld)
332
{
45070 ripley 333
    int      signal_Index;
334
    sigset_t sigset_MaskOld = downhill_Sigset_Mask;
4958 ripley 335
 
45070 ripley 336
    /* Make sure we're init'd */
337
    if (!downhill_Signal_Init())
338
    {
339
	return -1;
340
    }
4958 ripley 341
 
45070 ripley 342
    /* Return the current value */
343
    if (sigset_InfoOld != NULL)
344
    {
345
	*sigset_InfoOld = sigset_MaskOld;
346
    }
347
 
348
    /* Set the new mask */
349
    if (sigset_Info) {
350
	switch (mask_Function)
4958 ripley 351
	{
45070 ripley 352
	case SIG_BLOCK:
353
	    downhill_Sigset_Mask |= (*sigset_Info);
354
	    break;
355
	case SIG_UNBLOCK:
356
	    downhill_Sigset_Mask &= ~(*sigset_Info);
357
	    break;
358
	case SIG_SETMASK:
359
	    downhill_Sigset_Mask = *sigset_Info;
360
	    break;
361
	default:
362
	    errno = EINVAL;
363
	    return -1;
4958 ripley 364
	}
45070 ripley 365
    }
4958 ripley 366
 
45070 ripley 367
    /* And release any signals that were pending */
368
    for (signal_Index = 1;signal_Index < NSIG;signal_Index++)
369
    {
370
	if ((!sigismember(&downhill_Sigset_Mask,signal_Index)) &&
371
	    (sigismember(&sigset_MaskOld,signal_Index)) &&
372
	    (downhill_Signal_Info[signal_Index].signal_Count > 0))
4958 ripley 373
	{
45070 ripley 374
	    downhill_Signal_Info[signal_Index].signal_Count = 0;
375
	    raise(signal_Index);
4958 ripley 376
	}
45070 ripley 377
    }
4958 ripley 378
 
45070 ripley 379
    return 0;
4958 ripley 380
}
381
 
382
/* Set signal mask ========================================================= */
42642 ripley 383
int sigsetmask(int signal_MaskNew)
4958 ripley 384
{
45070 ripley 385
    int signal_MaskOld = downhill_Sigset_Mask;
4958 ripley 386
 
45070 ripley 387
    if (sigprocmask(SIG_SETMASK, &signal_MaskNew, NULL) == -1)
388
	return (int)-1;
4958 ripley 389
 
45070 ripley 390
    return signal_MaskOld;
4958 ripley 391
}
392
 
393
/* Add signals to mask ===================================================== */
42642 ripley 394
int sigblock(int signal_MaskNew)
4958 ripley 395
{
45070 ripley 396
    /* Block a specific group of signals */
397
    return sigsetmask(downhill_Sigset_Mask|signal_MaskNew);
4958 ripley 398
}
399
 
400
 
401
/* Hold a signal =========================================================== */
402
int sighold(int signal_Number)
403
{
45070 ripley 404
    /* Block a specific signal */
405
    if (sigblock(sigmask(signal_Number)) == -1)
406
    {
407
	return -1;
408
    }
4958 ripley 409
 
45070 ripley 410
    return 0;
4958 ripley 411
}
412
 
413
/* Release a signal ======================================================== */
414
int sigrelse(int signal_Number)
415
{
45070 ripley 416
    /* Release a specific signal */
417
    if (sigsetmask(downhill_Sigset_Mask&(~sigmask(signal_Number))) == -1)
418
    {
419
	return -1;
420
    }
4958 ripley 421
 
45070 ripley 422
    return 0;
4958 ripley 423
}
424
 
425
 
426
 
427
/* Pause until a signal ==================================================== */
428
int pause(void)
429
{
45070 ripley 430
    /* Wait for a signal */
431
    WaitForSingleObject(IGotASignal,INFINITE);
432
    /* And return if we were interrupted */
433
    errno = EINTR;
434
    return -1;
4958 ripley 435
}
436
 
437
 
438
/* Suspend the process until a signal ====================================== */
439
int sigsuspend(sigset_t* sigset_Info)
440
{
45070 ripley 441
    sigset_t sigset_MaskOriginal = downhill_Sigset_Mask;
4958 ripley 442
 
45070 ripley 443
    /* Set the new mask */
444
    sigprocmask(SIG_SETMASK,sigset_Info,NULL);
4958 ripley 445
 
45070 ripley 446
    /* Wait for the signal */
447
    pause();
4958 ripley 448
 
45070 ripley 449
    /* Reset the old mask */
450
    sigprocmask(SIG_SETMASK,&sigset_MaskOriginal,NULL);
4958 ripley 451
 
45070 ripley 452
    return -1;
4958 ripley 453
}