~vojtech-horky/helenos/numa

« back to all changes in this revision

Viewing changes to uspace/lib/posix/signal.c

  • Committer: Vojtech Horky
  • Date: 2011-09-28 15:13:08 UTC
  • mfrom: (538.1.714 helenos-mainline)
  • Revision ID: vojtechhorky@users.sourceforge.net-20110928151308-2pz4s2w035n48o8a
Merge mainline changes

Conflicts fixed without problems (mostly caused by separating
ABI into /abi/).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2011 Jiri Zarevucky
 
3
 * All rights reserved.
 
4
 *
 
5
 * Redistribution and use in source and binary forms, with or without
 
6
 * modification, are permitted provided that the following conditions
 
7
 * are met:
 
8
 *
 
9
 * - Redistributions of source code must retain the above copyright
 
10
 *   notice, this list of conditions and the following disclaimer.
 
11
 * - Redistributions in binary form must reproduce the above copyright
 
12
 *   notice, this list of conditions and the following disclaimer in the
 
13
 *   documentation and/or other materials provided with the distribution.
 
14
 * - The name of the author may not be used to endorse or promote products
 
15
 *   derived from this software without specific prior written permission.
 
16
 *
 
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 
18
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 
19
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 
20
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 
21
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 
22
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 
23
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 
24
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 
25
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 
26
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
27
 */
 
28
 
 
29
/** @addtogroup libposix
 
30
 * @{
 
31
 */
 
32
/** @file Signal handling.
 
33
 */
 
34
 
 
35
#define LIBPOSIX_INTERNAL
 
36
 
 
37
#include "signal.h"
 
38
#include "internal/common.h"
 
39
#include "limits.h"
 
40
#include "stdlib.h"
 
41
#include "string.h"
 
42
#include "errno.h"
 
43
 
 
44
#include "libc/fibril_synch.h"
 
45
#include "libc/task.h"
 
46
 
 
47
/* This file implements a fairly dumb and incomplete "simulation" of
 
48
 * POSIX signals. Since HelenOS doesn't support signals and mostly doesn't
 
49
 * have any equivalent functionality, most of the signals are useless. The
 
50
 * main purpose of this implementation is thus to help port applications using
 
51
 * signals with minimal modification, but if the application uses signals for
 
52
 * anything non-trivial, it's quite probable it won't work properly even if
 
53
 * it builds without problems.
 
54
 */
 
55
 
 
56
/* Used to serialize signal handling. */
 
57
static FIBRIL_MUTEX_INITIALIZE(_signal_mutex);
 
58
 
 
59
static LIST_INITIALIZE(_signal_queue);
 
60
 
 
61
static posix_sigset_t _signal_mask = 0;
 
62
 
 
63
#define DEFAULT_HANDLER { .sa_handler = SIG_DFL, \
 
64
    .sa_mask = 0, .sa_flags = 0, .sa_sigaction = NULL }
 
65
 
 
66
/* Actions associated with each signal number. */
 
67
static struct posix_sigaction _signal_actions[_TOP_SIGNAL + 1] = {
 
68
        DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
 
69
        DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
 
70
        DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
 
71
        DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
 
72
        DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
 
73
        DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, 
 
74
        DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER, DEFAULT_HANDLER
 
75
};
 
76
 
 
77
/**
 
78
 * Default signal handler. Executes the default action for each signal,
 
79
 * as reasonable within HelenOS.
 
80
 *
 
81
 * @param signo Signal number.
 
82
 */
 
83
void __posix_default_signal_handler(int signo)
 
84
{
 
85
        switch (signo) {
 
86
        case SIGABRT:
 
87
                abort();
 
88
        case SIGQUIT:
 
89
                fprintf(stderr, "Quit signal raised. Exiting.\n");
 
90
                exit(EXIT_FAILURE);
 
91
        case SIGINT:
 
92
                fprintf(stderr, "Interrupt signal caught. Exiting.\n");
 
93
                exit(EXIT_FAILURE);
 
94
        case SIGTERM:
 
95
                fprintf(stderr, "Termination signal caught. Exiting.\n");
 
96
                exit(EXIT_FAILURE);
 
97
        case SIGSTOP:
 
98
                fprintf(stderr, "Stop signal caught, but unsupported. Ignoring.\n");
 
99
                break;
 
100
        case SIGKILL:
 
101
                /* This will only occur when raise or similar is called. */
 
102
                /* Commit suicide. */
 
103
                task_kill(task_get_id());
 
104
                
 
105
                /* Should not be reached. */
 
106
                abort();
 
107
        case SIGFPE:
 
108
        case SIGBUS:
 
109
        case SIGILL:
 
110
        case SIGSEGV:
 
111
                posix_psignal(signo, "Hardware exception raised by user code");
 
112
                abort();
 
113
        case SIGSYS:
 
114
        case SIGXCPU:
 
115
        case SIGXFSZ:
 
116
        case SIGTRAP:
 
117
        case SIGHUP:
 
118
        case SIGPIPE:
 
119
        case SIGPOLL:
 
120
        case SIGURG:
 
121
        case SIGTSTP:
 
122
        case SIGTTIN:
 
123
        case SIGTTOU:
 
124
                posix_psignal(signo, "Unsupported signal caught");
 
125
                abort();
 
126
        case SIGCHLD:
 
127
        case SIGUSR1:
 
128
        case SIGUSR2:
 
129
        case SIGALRM:
 
130
        case SIGVTALRM:
 
131
        case SIGPROF:
 
132
        case SIGCONT:
 
133
                /* ignored */
 
134
                break;
 
135
        }
 
136
}
 
137
 
 
138
/**
 
139
 * Just an empty function to get an unique pointer value for comparison.
 
140
 *
 
141
 * @param signo Signal number.
 
142
 */
 
143
void __posix_hold_signal_handler(int signo)
 
144
{
 
145
        /* Nothing */
 
146
}
 
147
 
 
148
/**
 
149
 * Empty function to be used as ignoring handler.
 
150
 * 
 
151
 * @param signo Signal number.
 
152
 */
 
153
void __posix_ignore_signal_handler(int signo)
 
154
{
 
155
        /* Nothing */
 
156
}
 
157
 
 
158
/**
 
159
 * Clear the signal set.
 
160
 * 
 
161
 * @param set Pointer to the signal set.
 
162
 * @return Always returns zero.
 
163
 */
 
164
int posix_sigemptyset(posix_sigset_t *set)
 
165
{
 
166
        assert(set != NULL);
 
167
 
 
168
        *set = 0;
 
169
        return 0;
 
170
}
 
171
 
 
172
/**
 
173
 * Fill the signal set (i.e. add all signals).
 
174
 * 
 
175
 * @param set Pointer to the signal set.
 
176
 * @return Always returns zero.
 
177
 */
 
178
int posix_sigfillset(posix_sigset_t *set)
 
179
{
 
180
        assert(set != NULL);
 
181
 
 
182
        *set = UINT32_MAX;
 
183
        return 0;
 
184
}
 
185
 
 
186
/**
 
187
 * Add a signal to the set.
 
188
 * 
 
189
 * @param set Pointer to the signal set.
 
190
 * @param signo Signal number to add.
 
191
 * @return Always returns zero.
 
192
 */
 
193
int posix_sigaddset(posix_sigset_t *set, int signo)
 
194
{
 
195
        assert(set != NULL);
 
196
 
 
197
        *set |= (1 << signo);
 
198
        return 0;
 
199
}
 
200
 
 
201
/**
 
202
 * Delete a signal from the set.
 
203
 * 
 
204
 * @param set Pointer to the signal set.
 
205
 * @param signo Signal number to remove.
 
206
 * @return Always returns zero.
 
207
 */
 
208
int posix_sigdelset(posix_sigset_t *set, int signo)
 
209
{
 
210
        assert(set != NULL);
 
211
 
 
212
        *set &= ~(1 << signo);
 
213
        return 0;
 
214
}
 
215
 
 
216
/**
 
217
 * Inclusion test for a signal set.
 
218
 * 
 
219
 * @param set Pointer to the signal set.
 
220
 * @param signo Signal number to query.
 
221
 * @return 1 if the signal is in the set, 0 otherwise.
 
222
 */
 
223
int posix_sigismember(const posix_sigset_t *set, int signo)
 
224
{
 
225
        assert(set != NULL);
 
226
        
 
227
        return (*set & (1 << signo)) != 0;
 
228
}
 
229
 
 
230
/**
 
231
 * Unsafe variant of the sigaction() function.
 
232
 * Doesn't do any checking of its arguments and
 
233
 * does not deal with thread-safety.
 
234
 * 
 
235
 * @param sig
 
236
 * @param act
 
237
 * @param oact
 
238
 */
 
239
static void _sigaction_unsafe(int sig, const struct posix_sigaction *restrict act,
 
240
    struct posix_sigaction *restrict oact)
 
241
{
 
242
        if (oact != NULL) {
 
243
                memcpy(oact, &_signal_actions[sig],
 
244
                    sizeof(struct posix_sigaction));
 
245
        }
 
246
 
 
247
        if (act != NULL) {
 
248
                memcpy(&_signal_actions[sig], act,
 
249
                    sizeof(struct posix_sigaction));
 
250
        }
 
251
}
 
252
 
 
253
/**
 
254
 * Sets a new action for the given signal number.
 
255
 * 
 
256
 * @param sig Signal number to set action for.
 
257
 * @param act If not NULL, contents of this structure are
 
258
 *     used as the new action for the signal.
 
259
 * @param oact If not NULL, the original action associated with the signal
 
260
 *     is stored in the structure pointer to. 
 
261
 * @return -1 with errno set on failure, 0 on success.
 
262
 */
 
263
int posix_sigaction(int sig, const struct posix_sigaction *restrict act,
 
264
    struct posix_sigaction *restrict oact)
 
265
{
 
266
        if (sig > _TOP_SIGNAL || (act != NULL &&
 
267
            (sig == SIGKILL || sig == SIGSTOP))) {
 
268
                errno = EINVAL;
 
269
                return -1;
 
270
        }
 
271
 
 
272
        if (sig > _TOP_CATCHABLE_SIGNAL) {
 
273
                posix_psignal(sig,
 
274
                    "WARNING: registering handler for a partially"
 
275
                    " or fully unsupported signal. This handler may only be"
 
276
                    " invoked by the raise() function, which may not be what"
 
277
                    " the application developer intended");
 
278
        }
 
279
 
 
280
        fibril_mutex_lock(&_signal_mutex);
 
281
        _sigaction_unsafe(sig, act, oact);
 
282
        fibril_mutex_unlock(&_signal_mutex);
 
283
 
 
284
        return 0;
 
285
}
 
286
 
 
287
/**
 
288
 * Sets a new handler for the given signal number.
 
289
 * 
 
290
 * @param sig Signal number to set handler for.
 
291
 * @param func Handler function.
 
292
 * @return SIG_ERR on failure, original handler on success.
 
293
 */
 
294
void (*posix_signal(int sig, void (*func)(int)))(int)
 
295
{
 
296
        struct posix_sigaction new = {
 
297
                .sa_handler = func,
 
298
                .sa_mask = 0,
 
299
                .sa_flags = 0,
 
300
                .sa_sigaction = NULL
 
301
        };
 
302
        struct posix_sigaction old;
 
303
        if (posix_sigaction(sig, func == NULL ? NULL : &new, &old) == 0) {
 
304
                return old.sa_handler;
 
305
        } else {
 
306
                return SIG_ERR;
 
307
        }
 
308
}
 
309
 
 
310
typedef struct {
 
311
        link_t link;
 
312
        int signo;
 
313
        posix_siginfo_t siginfo;
 
314
} signal_queue_item;
 
315
 
 
316
/**
 
317
 * Queue blocked signal.
 
318
 *
 
319
 * @param signo Signal number.
 
320
 * @param siginfo Additional information about the signal.
 
321
 */
 
322
static void _queue_signal(int signo, posix_siginfo_t *siginfo)
 
323
{
 
324
        assert(signo >= 0 && signo <= _TOP_SIGNAL);
 
325
        assert(siginfo != NULL);
 
326
        
 
327
        signal_queue_item *item = malloc(sizeof(signal_queue_item));
 
328
        link_initialize(&(item->link));
 
329
        item->signo = signo;
 
330
        memcpy(&item->siginfo, siginfo, sizeof(posix_siginfo_t));
 
331
        list_append(&(item->link), &_signal_queue);
 
332
}
 
333
 
 
334
 
 
335
/**
 
336
 * Executes an action associated with the given signal.
 
337
 *
 
338
 * @param signo Signal number.
 
339
 * @param siginfo Additional information about the circumstances of this raise.
 
340
 * @return 0 if the action has been successfully executed. -1 if the signal is
 
341
 *     blocked.
 
342
 */
 
343
static int _raise_sigaction(int signo, posix_siginfo_t *siginfo)
 
344
{
 
345
        assert(signo >= 0 && signo <= _TOP_SIGNAL);
 
346
        assert(siginfo != NULL);
 
347
 
 
348
        fibril_mutex_lock(&_signal_mutex);
 
349
 
 
350
        struct posix_sigaction action = _signal_actions[signo];
 
351
 
 
352
        if (posix_sigismember(&_signal_mask, signo) ||
 
353
            action.sa_handler == SIG_HOLD) {
 
354
                _queue_signal(signo, siginfo);
 
355
                fibril_mutex_unlock(&_signal_mutex);
 
356
                return -1;
 
357
        }
 
358
 
 
359
        /* Modifying signal mask is unnecessary,
 
360
         * signal handling is serialized.
 
361
         */
 
362
 
 
363
        if ((action.sa_flags & SA_RESETHAND) && signo != SIGILL && signo != SIGTRAP) {
 
364
                _signal_actions[signo] = (struct posix_sigaction) DEFAULT_HANDLER;
 
365
        }
 
366
 
 
367
        if (action.sa_flags & SA_SIGINFO) {
 
368
                assert(action.sa_sigaction != NULL);
 
369
                action.sa_sigaction(signo, siginfo, NULL);
 
370
        } else {
 
371
                assert(action.sa_handler != NULL);
 
372
                action.sa_handler(signo);
 
373
        }
 
374
 
 
375
        fibril_mutex_unlock(&_signal_mutex);
 
376
 
 
377
        return 0;
 
378
}
 
379
 
 
380
/**
 
381
 * Raise all unblocked previously queued signals.
 
382
 */
 
383
static void _dequeue_unblocked_signals()
 
384
{
 
385
        link_t *iterator = _signal_queue.head.next;
 
386
        link_t *next;
 
387
        
 
388
        while (iterator != &(_signal_queue).head) {
 
389
                next = iterator->next;
 
390
                
 
391
                signal_queue_item *item =
 
392
                    list_get_instance(iterator, signal_queue_item, link);
 
393
                
 
394
                if (!posix_sigismember(&_signal_mask, item->signo) &&
 
395
                    _signal_actions[item->signo].sa_handler != SIG_HOLD) {
 
396
                        list_remove(&(item->link));
 
397
                        _raise_sigaction(item->signo, &(item->siginfo));
 
398
                        free(item);
 
399
                }
 
400
                
 
401
                iterator = next;
 
402
        }
 
403
}
 
404
 
 
405
/**
 
406
 * Raise a signal for the calling process.
 
407
 * 
 
408
 * @param sig Signal number.
 
409
 * @return -1 with errno set on failure, 0 on success.
 
410
 */
 
411
int posix_raise(int sig)
 
412
{
 
413
        if (sig >= 0 && sig <= _TOP_SIGNAL) {
 
414
                posix_siginfo_t siginfo = {
 
415
                        .si_signo = sig,
 
416
                        .si_code = SI_USER
 
417
                };
 
418
                return _raise_sigaction(sig, &siginfo);
 
419
        } else {
 
420
                errno = EINVAL;
 
421
                return -1;
 
422
        }
 
423
}
 
424
 
 
425
/**
 
426
 * Raises a signal for a selected process.
 
427
 * 
 
428
 * @param pid PID of the process for which the signal shall be raised.
 
429
 * @param signo Signal to raise.
 
430
 * @return -1 with errno set on failure (possible errors include unsupported
 
431
 *     action, invalid signal number, lack of permissions, etc.), 0 on success.
 
432
 */
 
433
int posix_kill(posix_pid_t pid, int signo)
 
434
{
 
435
        if (pid < 1) {
 
436
                // TODO
 
437
                errno = ENOTSUP;
 
438
                return -1;
 
439
        }
 
440
 
 
441
        if (signo > _TOP_SIGNAL) {
 
442
                errno = EINVAL;
 
443
                return -1;
 
444
        }
 
445
 
 
446
        if (pid == (posix_pid_t) task_get_id()) {
 
447
                return posix_raise(signo);
 
448
        }
 
449
 
 
450
        switch (signo) {
 
451
        case SIGKILL:
 
452
                task_kill(pid);
 
453
                break;
 
454
        default:
 
455
                /* Nothing else supported yet. */
 
456
                errno = ENOTSUP;
 
457
                return -1;
 
458
        }
 
459
 
 
460
        return 0;
 
461
}
 
462
 
 
463
/**
 
464
 * Send a signal to a process group. Always fails at the moment because of
 
465
 * lack of this functionality in HelenOS.
 
466
 * 
 
467
 * @param pid PID of the process group.
 
468
 * @param sig Signal number.
 
469
 * @return -1 on failure, 0 on success (see kill()).
 
470
 */
 
471
int posix_killpg(posix_pid_t pid, int sig)
 
472
{
 
473
        assert(pid > 1);
 
474
        return posix_kill(-pid, sig);
 
475
}
 
476
 
 
477
/**
 
478
 * Outputs information about the signal to the standard error stream.
 
479
 * 
 
480
 * @param pinfo SigInfo struct to write.
 
481
 * @param message String to output alongside human-readable signal description.
 
482
 */
 
483
void posix_psiginfo(const posix_siginfo_t *pinfo, const char *message)
 
484
{
 
485
        assert(pinfo != NULL);
 
486
        posix_psignal(pinfo->si_signo, message);
 
487
        // TODO: print si_code
 
488
}
 
489
 
 
490
/**
 
491
 * Outputs information about the signal to the standard error stream.
 
492
 * 
 
493
 * @param signum Signal number.
 
494
 * @param message String to output alongside human-readable signal description.
 
495
 */
 
496
void posix_psignal(int signum, const char *message)
 
497
{
 
498
        char *sigmsg = posix_strsignal(signum);
 
499
        if (message == NULL || *message == '\0') {
 
500
                fprintf(stderr, "%s\n", sigmsg);
 
501
        } else {
 
502
                fprintf(stderr, "%s: %s\n", message, sigmsg);
 
503
        }
 
504
}
 
505
 
 
506
/**
 
507
 * Manipulate the signal mask of the calling thread.
 
508
 * 
 
509
 * @param how What to do with the mask.
 
510
 * @param set Signal set to work with.
 
511
 * @param oset If not NULL, the original signal mask is coppied here.
 
512
 * @return 0 success, errorcode on failure.
 
513
 */
 
514
int posix_thread_sigmask(int how, const posix_sigset_t *restrict set,
 
515
    posix_sigset_t *restrict oset)
 
516
{
 
517
        fibril_mutex_lock(&_signal_mutex);
 
518
 
 
519
        if (oset != NULL) {
 
520
                *oset = _signal_mask;
 
521
        }
 
522
        if (set != NULL) {
 
523
                switch (how) {
 
524
                case SIG_BLOCK:
 
525
                        _signal_mask |= *set;
 
526
                        break;
 
527
                case SIG_UNBLOCK:
 
528
                        _signal_mask &= ~*set;
 
529
                        break;
 
530
                case SIG_SETMASK:
 
531
                        _signal_mask = *set;
 
532
                        break;
 
533
                default:
 
534
                        fibril_mutex_unlock(&_signal_mutex);
 
535
                        return EINVAL;
 
536
                }
 
537
        }
 
538
        
 
539
        _dequeue_unblocked_signals();
 
540
 
 
541
        fibril_mutex_unlock(&_signal_mutex);
 
542
 
 
543
        return 0;
 
544
}
 
545
 
 
546
/**
 
547
 * Manipulate the signal mask of the process.
 
548
 * 
 
549
 * @param how What to do with the mask.
 
550
 * @param set Signal set to work with.
 
551
 * @param oset If not NULL, the original signal mask is coppied here.
 
552
 * @return 0 on success, -1 with errno set on failure.
 
553
 */
 
554
int posix_sigprocmask(int how, const posix_sigset_t *restrict set,
 
555
    posix_sigset_t *restrict oset)
 
556
{
 
557
        int result = posix_thread_sigmask(how, set, oset);
 
558
        if (result != 0) {
 
559
                errno = result;
 
560
                return -1;
 
561
        }
 
562
        return 0;
 
563
}
 
564
 
 
565
/** @}
 
566
 */