You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

267 lines
6.8 KiB

/*
* Copyright 2002-2019 Intel Corporation.
*
* This software is provided to you as Sample Source Code as defined in the accompanying
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
* section 1.L.
*
* This software and the related documents are provided as is, with no express or implied
* warranties, other than those that are expressly stated in the License.
*/
/*
* There are three tests that use this application:
* 1. ppollEmulationSuccessful.test- tests the correctness of the emulation of a successful ppoll system call.
* 2. ppollEmulationTimeOut.test- tests the correctness of the emulation of a ppoll system call
* which was interrupted by a time out.
* 3. ppollEmulationSignalInterrupt.test- tests the correctness of the emulation of a ppoll system call
* which was interrupted by a signal.
* 4. ppollEmulationNullSigmask.test - tests that Pin properly handles a NULL signal mask passed to the ppoll
* system call.
*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <poll.h>
#include <setjmp.h>
#include <errno.h>
#include <sys/stat.h>
#define MSG "MSG\n"
volatile int istimer = 0;
pthread_t main_th;
volatile bool stop = false;
const char * logFileName = NULL;
const char * pipeName = NULL;
int fdMainThread = -1;
enum ExitType {
RES_SUCCESS = 0, // 0
RES_OPEN_FILE_ERROR, // 1
RES_MAKE_PIPE_ERROR, // 2
RES_INVALID_ARGS, // 3
RES_OPEN_FD_ERROR, // 4
RES_WRITE_TO_FD_ERROR, // 5
RES_WRONG_SIGNAL_ERROR, // 6
RES_THREADCREATE_FAILED, // 7
RES_SIGACTION_FAILED, // 8
RES_ERROR // 9
};
void * thread_handler(void *arg)
{
int fdWriteThread = open(pipeName, O_RDWR );
if (fdWriteThread < 0)
{
perror("Failed to open fd");
exit(RES_OPEN_FD_ERROR);
}
for (unsigned int i = 0; i < 10; i++)
{
sleep(10);
int ret = write(fdWriteThread, MSG, sizeof(MSG));
if (ret< 0)
{
perror("Failed to write to fd");
close(fdWriteThread);
exit(RES_WRITE_TO_FD_ERROR);
}
}
stop = true;
close(fdWriteThread);
return NULL;
}
void * timer_handler(void *arg)
{
struct timespec tm;
for (unsigned int i = 0; i < 100; i++)
{
tm.tv_sec = 0;
tm.tv_nsec = 250*1000*1000;
nanosleep(&tm, NULL);
pthread_kill(main_th, SIGALRM);
}
return NULL;
}
void sig_handler (int signo, siginfo_t *info, void *context)
{
if (signo == SIGALRM)
{
istimer = 1;
}
else
{
printf("Signal %d received\n", signo);
exit(RES_WRONG_SIGNAL_ERROR);
}
}
void *do_nothing(void *)
{
while(1) sleep(5);
return NULL;
}
void poll_exit()
{
close(fdMainThread);
remove(pipeName);
}
/*
Expected argv arguments:
[1] testType
[2] log file name
[3] pipe name
*/
int main(int argc, char* argv[] )
{
if(argc != 4)
{
fprintf(stderr, "Not enough arguments\n" );
fflush(stderr);
return RES_INVALID_ARGS;
}
int testType = atoi (argv[1]);
logFileName = argv[2];
FILE * pFile = fopen (logFileName , "w");
if (pFile == NULL)
{
perror ("Error opening file");
return RES_OPEN_FILE_ERROR;
}
pipeName = argv[3];
pthread_t th1;
sigset_t ppollSigmask;
sigemptyset(&ppollSigmask);
sigset_t* ppollSigmaskPtr = &ppollSigmask;
struct pollfd list;
char buf[20];
struct sigaction sigact;
struct timespec tem;
int mode = S_IWGRP | S_IWOTH | S_IWUSR | S_IRGRP | S_IROTH | S_IRUSR;
if (mkfifo(pipeName, mode) < 0)
{
perror("mkfifo");
return RES_MAKE_PIPE_ERROR;
}
chmod(pipeName, mode);
fdMainThread = open(pipeName, O_RDWR);
if (fdMainThread < 0)
{
perror("Failed to open fd");
return RES_OPEN_FD_ERROR;
}
atexit(poll_exit);
main_th = pthread_self();
switch (testType)
{
case 4:
ppollSigmaskPtr = NULL;
// fallthrough to case 1
case 1:
{
if (pthread_create(&th1, NULL, thread_handler, 0) != 0)
{
printf("pthread_create error\n");
return RES_THREADCREATE_FAILED;
}
tem.tv_sec = 60;
tem.tv_nsec = 0;
break;
}
case 2:
{
if (pthread_create(&th1, NULL, timer_handler, 0) != 0)
{
printf("pthread_create error\n");
return RES_THREADCREATE_FAILED;
}
tem.tv_sec = 60;
tem.tv_nsec = 0;
sigaddset(&ppollSigmask, SIGQUIT);
int signalsToHandle[] = {SIGINT, SIGTERM, SIGALRM};
for(unsigned int i = 0; i < sizeof(signalsToHandle)/sizeof(int) ; i++)
{
sigact.sa_flags = SA_SIGINFO | SA_NODEFER;
sigact.sa_sigaction = sig_handler;
sigemptyset (&sigact.sa_mask);
if (sigaction (signalsToHandle[i], &sigact, 0) < 0) {
perror("sigaction failed");
return RES_SIGACTION_FAILED;
}
}
break;
}
case 3:
{
if (pthread_create(&th1, NULL, do_nothing, 0) != 0)
{
printf("pthread_create error\n");
return RES_THREADCREATE_FAILED;
}
tem.tv_sec = 0;
tem.tv_nsec = 250*1000*1000;
break;
}
default:
// do nothing
break;
}
while (!stop)
{
usleep(1000);
list.fd = fdMainThread;
list.events = (POLLIN | POLLHUP | POLLERR | POLLNVAL);
int ret = ppoll(&list, 1, &tem, ppollSigmaskPtr);
if(ret == 0)
{
fprintf(pFile, "The call timed out and no file descriptors were ready\n");
stop = true;
}
else if (ret < 0)
{
if ((errno == EINTR) && istimer)
{
istimer = 0;
fprintf(pFile,"sigalarm interrupted the ppoll system call\n");
stop = true;
}
else
{
fprintf(stderr,"received wrong signal\n");
return RES_WRONG_SIGNAL_ERROR;
}
}
else if (list.revents & POLLIN)
{
fprintf(pFile, "PPOLL succeeded:%d\n", (int)ret);
int count = read(fdMainThread, buf, 20);
if (count<0) perror("read"); else fprintf(pFile, "ppoll succeeded\n");;
stop = true;
}
else
{
fprintf(stderr, "other error\n");
return RES_ERROR;
}
}
return RES_SUCCESS;
}