blob: f1edc3ff05d57fc0d2778fb2e908d647c32d2d8f [file] [log] [blame]
/*
* Copyright (c) 2004, Bull S.A.. All rights reserved.
* Copyright (c) 2017, Linux Test Project
* Created by: Sebastien Decugis
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it would be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write the Free Software Foundation, Inc.,
*
* This sample test aims to check the following assertion:
* The function does not return EINTR
*
* The steps are:
* -> continuously send SIGUSR1 to a thread which runs pthread_create()
* -> check that EINTR is never returned
*/
/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
#define _POSIX_C_SOURCE 200112L
/* Some routines are part of the XSI Extensions */
#ifndef WITHOUT_XOPEN
#define _XOPEN_SOURCE 600
#endif
#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <stdlib.h>
#include <unistd.h>
#include "../testfrmw/testfrmw.h"
#include "../testfrmw/testfrmw.c"
#include "../testfrmw/threads_scenarii.c"
#include "safe_helpers.h"
#define RUN_TIME_USEC (2*1000*1000)
#define SIGNALS_WITHOUT_DELAY 100
/* total number of signals sent */
static unsigned long count_sig;
/* sleep [us] in between signals */
static volatile unsigned long sleep_time;
/* number of pthread_create scenarios tested */
static unsigned long count_ope;
static unsigned long long current_time_usec(void)
{
struct timeval now;
SAFE_FUNC(gettimeofday(&now, NULL));
return now.tv_sec * 1000000LL + now.tv_usec;
}
/* the following function keeps sending signal to the process */
static void *sendsig(void *arg)
{
static sigset_t usersigs;
(void)arg;
pid_t process = getpid();
/* block the signal SIGUSR1 for this THREAD */
SAFE_FUNC(sigemptyset(&usersigs));
SAFE_FUNC(sigaddset(&usersigs, SIGUSR1));
SAFE_PFUNC(pthread_sigmask(SIG_BLOCK, &usersigs, NULL));
while (1) {
/*
* Keep increasing sleeptime to make sure we progress
* allow SIGNALS_WITHOUT_DELAY signals without any pause,
* then start increasing sleep_time to make sure all threads
* can progress.
*/
sleep_time++;
if (sleep_time / SIGNALS_WITHOUT_DELAY > 0)
usleep(sleep_time / SIGNALS_WITHOUT_DELAY);
count_sig++;
SAFE_FUNC(kill(process, SIGUSR1));
}
return NULL;
}
static void sighdl1(int sig)
{
(void)sig;
}
static void *threaded(void *arg)
{
int ret;
/* Signal we're done (especially in case of a detached thread) */
do {
ret = sem_post(&scenarii[sc].sem);
} while ((ret == -1) && (errno == EINTR));
if (ret == -1)
UNRESOLVED(errno, "Failed to wait for the semaphore");
return arg;
}
/* create threads and check that EINTR is never returned */
static void test(void)
{
int ret = 0;
pthread_t child;
pthread_t th_sig1;
struct sigaction sa;
pthread_attr_t attr;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = sighdl1;
SAFE_FUNC(sigaction(SIGUSR1, &sa, NULL));
SAFE_PFUNC(pthread_attr_init(&attr));
SAFE_PFUNC(pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED));
SAFE_PFUNC(pthread_create(&th_sig1, &attr, sendsig, NULL));
for (sc = 0; sc < NSCENAR; sc++) {
/* reset sleep time for signal thread */
sleep_time = 0;
ret = pthread_create(&child, &scenarii[sc].ta, threaded, NULL);
if (ret == EINTR)
FAILED("pthread_create returned EINTR");
switch (scenarii[sc].result) {
case 0: /* Operation was expected to succeed */
if (ret != 0)
UNRESOLVED(ret, "Failed to create this thread");
break;
case 1: /* Operation was expected to fail */
if (ret == 0) {
UNRESOLVED(-1, "An error was expected but"
" the thread creation succeeded");
}
break;
case 2: /* We did not know the expected result */
default:
break;
}
if (ret != 0)
continue;
/* The new thread is running */
/* Just wait for the thread to terminate */
do {
ret = sem_wait(&scenarii[sc].sem);
} while ((ret == -1) && (errno == EINTR));
if (ret == -1)
UNRESOLVED(errno, "Failed to wait for the semaphore");
if (scenarii[sc].detached == 0)
SAFE_PFUNC(pthread_join(child, NULL));
}
}
static void main_loop(void)
{
int child_count = 0;
int ret;
int status;
int stat_pipe[2];
pid_t child;
unsigned long long usec_start, usec;
unsigned long child_count_sig;
usec_start = current_time_usec();
do {
fflush(stdout);
SAFE_FUNC(pipe(stat_pipe));
child = SAFE_FUNC(fork());
if (child == 0) {
count_sig = 0;
close(stat_pipe[0]);
test();
SAFE_FUNC(write(stat_pipe[1], &count_sig,
sizeof(count_sig)));
close(stat_pipe[1]);
exit(0);
}
close(stat_pipe[1]);
SAFE_FUNC(read(stat_pipe[0], &child_count_sig,
sizeof(count_sig)));
close(stat_pipe[0]);
count_sig += child_count_sig;
ret = waitpid(child, &status, 0);
if (ret != child)
UNRESOLVED(errno, "Waitpid returned the wrong PID");
if (!WIFEXITED(status)) {
output("status: %d\n", status);
FAILED("Child exited abnormally");
}
if (WEXITSTATUS(status) != 0) {
output("exit status: %d\n", WEXITSTATUS(status));
FAILED("An error occurred in child");
}
child_count++;
count_ope += NSCENAR;
usec = current_time_usec();
} while ((usec - usec_start) < RUN_TIME_USEC);
output("Test spawned %d child processes.\n", child_count);
output("Test finished after %lu usec.\n", usec - usec_start);
}
int main(void)
{
output_init();
scenar_init();
main_loop();
scenar_fini();
output("Test executed successfully.\n");
output(" %d thread creations.\n", count_ope);
output(" %d signals were sent meanwhile.\n", count_sig);
PASSED;
}