Home | History | Annotate | Download | only in sigaction
      1 /*
      2  * Copyright (c) 2011, Novell Inc.  All rights reserved.
      3  * Author: Peter W. Morreale <pmorreale (at) novell.com>
      4  *
      5  * Based on a similar original program written by Sebastien Decugis
      6  *
      7  * This program is free software; you can redistribute it and/or modify it
      8  * under the terms of version 2 of the GNU General Public License as
      9  * published by the Free Software Foundation.
     10  *
     11  * This program is distributed in the hope that it would be useful, but
     12  * WITHOUT ANY WARRANTY; without even the implied warranty of
     13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
     14  *
     15  * You should have received a copy of the GNU General Public License along
     16  * with this program; if not, write the Free Software Foundation, Inc.,
     17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
     18  *
     19  * This sample test aims to check the following assertions:
     20  *
     21  * If SA_RESTART is set in sa_flags, interruptible function interrupted
     22  * by signal shall restart silently.
     23  *
     24  */
     25 
     26 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
     27 #define _POSIX_C_SOURCE 200112L
     28 
     29 /* This test tests for an XSI feature */
     30 #define _XOPEN_SOURCE 600
     31 
     32 #include <pthread.h>
     33 #include <stdarg.h>
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <string.h>
     37 #include <unistd.h>
     38 #include <semaphore.h>
     39 #include <signal.h>
     40 #include <errno.h>
     41 #include <posixtest.h>
     42 
     43 /*
     44  * Define an array of signals we want to test against.
     45  * Add more if desired.
     46  */
     47 
     48 struct sig_info {
     49 	int sig;
     50 	char *sig_name;
     51 	char caught;
     52 };
     53 
     54 static struct sig_info sigs[] = {
     55 	{SIGHUP, "SIGHUP", 0},
     56 	{SIGINT, "SIGINT", 0},
     57 	{SIGQUIT, "SIGQUIT", 0},
     58 	{SIGILL, "SIGILL", 0},
     59 	{SIGTRAP, "SIGTRAP", 0},
     60 	{SIGABRT, "SIGABRT", 0},
     61 	{SIGBUS, "SIGBUS", 0},
     62 	{SIGFPE, "SIGFPE", 0},
     63 	{SIGUSR1, "SIGUSR1", 0},
     64 	{SIGSEGV, "SIGSEGV", 0},
     65 	{SIGUSR2, "SIGUSR2", 0},
     66 	{SIGPIPE, "SIGPIPE", 0},
     67 	{SIGALRM, "SIGALRM", 0},
     68 	{SIGTERM, "SIGTERM", 0},
     69 #ifdef SIGSTKFLT
     70 	{SIGSTKFLT, "SIGSTKFLT", 0},
     71 #endif
     72 	{SIGCHLD, "SIGCHLD", 0},
     73 	{SIGCONT, "SIGCONT", 0},
     74 	{SIGTSTP, "SIGTSTP", 0},
     75 	{SIGTTIN, "SIGTTIN", 0},
     76 	{SIGTTOU, "SIGTTOU", 0},
     77 	{SIGURG, "SIGURG", 0},
     78 	{SIGXCPU, "SIGXCPU", 0},
     79 	{SIGXFSZ, "SIGXFSZ", 0},
     80 	{SIGVTALRM, "SIGVTALRM", 0},
     81 	{SIGPROF, "SIGPROF", 0},
     82 	{SIGWINCH, "SIGWINCH", 0},
     83 	{SIGPOLL, "SIGPOLL", 0},
     84 	{-1, NULL, 0}		/* add  real time sigs? */
     85 };
     86 
     87 static volatile int ready;
     88 static sem_t sem;
     89 
     90 /* Lookup */
     91 struct sig_info *lookup(int signo)
     92 {
     93 	struct sig_info *s = &sigs[0];
     94 
     95 	while (s->sig > 0) {
     96 		if (s->sig == signo)
     97 			return s;
     98 		s++;
     99 	}
    100 	return NULL;
    101 }
    102 
    103 /* Handler function */
    104 void handler(int signo)
    105 {
    106 	struct sig_info *s;
    107 
    108 	s = lookup(signo);
    109 	if (s)
    110 		s->caught = 1;
    111 }
    112 
    113 /* Thread function */
    114 void *threaded(void *arg)
    115 {
    116 	int rc;
    117 	int status = PTS_PASS;
    118 	struct sched_param sp = { 10 };
    119 	struct sig_info *s = arg;
    120 
    121 	/*
    122 	 * Move into SCHED_FIFO to help ensure we are waiting in
    123 	 * sem_wait when the signal is delivered
    124 	 */
    125 	rc = pthread_setschedparam(pthread_self(), SCHED_FIFO, &sp);
    126 	if (rc) {
    127 		printf("Failed: pthread_setschedparam(SCHED_FIFO), root?\n");
    128 
    129 		if (rc == EPERM)
    130 			exit(PTS_UNTESTED);
    131 		else
    132 			exit(PTS_UNRESOLVED);
    133 	}
    134 
    135 	ready = 1;
    136 
    137 	rc = sem_wait(&sem);
    138 	if (rc) {
    139 		status = PTS_UNRESOLVED;
    140 		printf("Failed: sem_wait(): errno: %s signal: %s\n",
    141 		       strerror(errno), s->sig_name);
    142 		if (errno == EINTR)
    143 			status = PTS_FAIL;
    144 	}
    145 
    146 	return (void *)((long)status);
    147 }
    148 
    149 int test_sig(struct sig_info *s)
    150 {
    151 	int rc;
    152 	int status = PTS_UNRESOLVED;
    153 	pthread_t child;
    154 	char *label;
    155 	void *thread_status;
    156 
    157 	label = "sem_init()";
    158 	rc = sem_init(&sem, 0, 0);
    159 	if (rc)
    160 		goto done;
    161 
    162 	/* reset flag */
    163 	ready = 0;
    164 
    165 	label = "pthread_create()";
    166 	errno = pthread_create(&child, NULL, threaded, s);
    167 	if (errno)
    168 		goto done;
    169 
    170 	/*
    171 	 * sync on the ready flag.  Since the child is running in
    172 	 * SCHED_FIFO, it likely will continue running and wind up in
    173 	 * sem_wait() prior to this thread sending a signal.
    174 	 *
    175 	 * Do one more yield for good luck.
    176 	 */
    177 	while (!ready)
    178 		sched_yield();
    179 	sched_yield();
    180 
    181 	label = "pthread_kill()";
    182 	errno = pthread_kill(child, s->sig);
    183 	if (errno)
    184 		goto done;
    185 
    186 	while (!s->caught)
    187 		sched_yield();
    188 
    189 	label = "sem_post()";
    190 	rc = sem_post(&sem);
    191 	if (rc)
    192 		goto done;
    193 
    194 	label = "pthread_join()";
    195 	errno = pthread_join(child, &thread_status);
    196 	if (errno)
    197 		goto done;
    198 
    199 	sem_destroy(&sem);
    200 
    201 	status = ((long)thread_status) & 0xFFFFFFFF;
    202 
    203 	return status;
    204 
    205 done:
    206 	printf("Failed: func: %s, rc: %d errno: %s signal: %s\n",
    207 	       label, rc, strerror(errno), s->sig_name);
    208 	return status;
    209 }
    210 
    211 int main(void)
    212 {
    213 	int rc = 0;
    214 	struct sig_info *s = &sigs[0];
    215 	struct sigaction sa;
    216 	struct sigaction sa_org;
    217 
    218 	sa.sa_flags = SA_RESTART;
    219 	sa.sa_handler = handler;
    220 
    221 	while (s->sig > 0) {
    222 		sigemptyset(&sa.sa_mask);
    223 		rc = sigaction(s->sig, &sa, &sa_org);
    224 		if (rc)
    225 			goto done;
    226 
    227 		rc = test_sig(s);
    228 		if (rc != PTS_PASS)
    229 			break;
    230 
    231 		sigaction(s->sig, &sa_org, NULL);
    232 		s++;
    233 	}
    234 
    235 	if (rc == PTS_PASS)
    236 		printf("Test PASSED\n");
    237 
    238 	return rc;
    239 
    240 done:
    241 	printf("Failed: sigaction(): errno: %s, signal: %s\n",
    242 	       strerror(errno), s->sig_name);
    243 	return PTS_FAIL;
    244 }
    245