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.
305 lines
7.9 KiB
305 lines
7.9 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.
|
|
*/
|
|
|
|
/*
|
|
* This application checks the correctness of the retrieve and alteration
|
|
* of the thread sigmask when a tool retrieves / alters it.
|
|
*/
|
|
|
|
#include <pthread.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
#include <signal.h>
|
|
#include <cstdio>
|
|
#include <errno.h>
|
|
#include <cstring>
|
|
#include <cstdlib>
|
|
#include <semaphore.h>
|
|
#include <sys/syscall.h>
|
|
|
|
|
|
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
static pthread_mutex_t mutex1 = PTHREAD_MUTEX_INITIALIZER;
|
|
static pthread_t one_tid, two_tid;
|
|
static FILE * fd_signals;
|
|
static char * FILE_NAME = const_cast<char *>("signal_list.txt");
|
|
static int MAX_SIZE = 128; /*maximum line size*/
|
|
static int syncPipe[2];
|
|
static volatile int iteration = 0;
|
|
|
|
|
|
extern "C" bool WaitChangeSigmask()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
void EmptySignalHandler(int param)
|
|
{
|
|
}
|
|
|
|
int mutex_lock_check_errno(pthread_mutex_t *mtx)
|
|
{
|
|
do
|
|
{
|
|
int r = pthread_mutex_lock(mtx);
|
|
if (0 == r)
|
|
{
|
|
return r;
|
|
}
|
|
}
|
|
while (EINTR == errno);
|
|
perror("pthread_mutex_lock");
|
|
abort();
|
|
return -1;
|
|
}
|
|
|
|
int mutex_unlock_check_errno(pthread_mutex_t *mtx)
|
|
{
|
|
int r = pthread_mutex_unlock(mtx);
|
|
if (0 != r)
|
|
{
|
|
perror("pthread_mutex_unlock");
|
|
abort();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* block all the signals relevant to this test
|
|
* Note that we don't want to block SIGTERM, SIGINT and such because we want
|
|
* to allow the test termination in case of cancellation
|
|
*/
|
|
void BlockUserSignals()
|
|
{
|
|
sigset_t sigmask;
|
|
sigemptyset(&sigmask);
|
|
sigaddset(&sigmask, SIGUSR1);
|
|
sigaddset(&sigmask, SIGUSR2);
|
|
pthread_sigmask(SIG_BLOCK, &sigmask, NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
* block only the signals in the list: "signalsListToBlock"
|
|
*/
|
|
void BlockSignals(int signalsListToBlock[] , int len, sigset_t * sigmask)
|
|
{
|
|
sigemptyset(sigmask);
|
|
int i;
|
|
for(i=0; i< len; ++i)
|
|
sigaddset(sigmask, signalsListToBlock[i]);
|
|
pthread_sigmask(SIG_SETMASK, sigmask, NULL);
|
|
}
|
|
|
|
|
|
/*
|
|
* A thread function that processes SIGUSR1 and SIGUSR2 signals sent by the SignalSender thread function
|
|
*/
|
|
void * SignalReceiver(void *arg)
|
|
{
|
|
fd_signals = fopen(FILE_NAME, "w");
|
|
int sigList[1] = {SIGUSR2};
|
|
sigset_t sigmask;
|
|
BlockSignals(sigList, 1, &sigmask);
|
|
signal(SIGUSR2, EmptySignalHandler);
|
|
signal(SIGUSR1, EmptySignalHandler);
|
|
while (iteration<10)
|
|
{
|
|
int numSigReceived=0;
|
|
pthread_sigmask(SIG_SETMASK, NULL, &sigmask);
|
|
|
|
time_t start = time(NULL);
|
|
|
|
// wait for the signal for at most 2 seconds
|
|
while ((time(NULL) - start) < 2)
|
|
{
|
|
if (0 != sigpending(&sigmask))
|
|
{
|
|
perror("sigpending");
|
|
exit(2);
|
|
}
|
|
if (sigismember(&sigmask, SIGUSR1) || sigismember(&sigmask, SIGUSR2))
|
|
{
|
|
int err;
|
|
do
|
|
{
|
|
// sigwait will not block since we already have signal pending
|
|
err = sigwait(&sigmask, &numSigReceived);
|
|
}
|
|
while (err == EINTR);
|
|
if (0 != err)
|
|
{
|
|
fprintf(stderr, "sigwait failed with errno %d\n", err);
|
|
exit(2);
|
|
}
|
|
break;
|
|
}
|
|
sched_yield();
|
|
}
|
|
|
|
signal(SIGUSR2, EmptySignalHandler);
|
|
signal(SIGUSR1, EmptySignalHandler);
|
|
|
|
if(numSigReceived == SIGUSR2)
|
|
{
|
|
iteration++;
|
|
fprintf(fd_signals, "%d", 2 );
|
|
}
|
|
if(numSigReceived == SIGUSR1)
|
|
{
|
|
iteration++;
|
|
fprintf(fd_signals, "%d", 1 );
|
|
}
|
|
mutex_unlock_check_errno(&mutex);
|
|
mutex_lock_check_errno(&mutex1);
|
|
}
|
|
fclose(fd_signals);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* Send repeatedly signals (SIGUSR1 and SIGUSR2) to the thread which starts execution by invoking the function
|
|
* SignalReceiver
|
|
*/
|
|
void * SignalSender(void *arg)
|
|
{
|
|
bool wasSigmaskChanged = false;
|
|
sigset_t sigmask;
|
|
int sigList[2] = {SIGUSR1, SIGUSR2};
|
|
BlockSignals(sigList, 2, &sigmask);
|
|
mutex_lock_check_errno(&mutex);
|
|
do
|
|
{
|
|
pthread_kill(two_tid, SIGUSR2); /* Delivers a signal*/
|
|
pthread_kill(two_tid, SIGUSR1); /* Delivers a signal*/
|
|
|
|
if(iteration==2 && !wasSigmaskChanged)
|
|
{
|
|
wasSigmaskChanged = true;
|
|
close(syncPipe[1]); // close the write side - releasing the child process to start PIN
|
|
while(!WaitChangeSigmask()) sched_yield();
|
|
}
|
|
|
|
mutex_unlock_check_errno(&mutex1);
|
|
mutex_lock_check_errno(&mutex);
|
|
}
|
|
while (pthread_kill(two_tid, 0) == 0); // while two_tid is alive
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*
|
|
* Main function
|
|
*
|
|
* Expected arguments:
|
|
* 1 - output file name
|
|
* 2 - Pin executable
|
|
* 3 - "-slow_asserts" (optional)
|
|
* 4 - tool name
|
|
*/
|
|
int main(int argc, char * argv[])
|
|
{
|
|
pid_t parentPid = getpid();
|
|
|
|
bool validNumberOfArgs = true;
|
|
if (4 == argc)
|
|
{
|
|
for (int i = 0; i < argc; ++i)
|
|
{
|
|
if (0 == strcmp("-slow_asserts", argv[i])) // not expecting -slow_asserts
|
|
{
|
|
validNumberOfArgs = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else if (5 == argc)
|
|
{
|
|
if (0 != strcmp("-slow_asserts", argv[3])) // expecting -slow_asserts at position 3
|
|
{
|
|
validNumberOfArgs = false;
|
|
}
|
|
}
|
|
else validNumberOfArgs = false; // illegal number of arguments
|
|
|
|
if (!validNumberOfArgs)
|
|
{
|
|
fprintf(stderr, "Usage: %s <output file> <PIN exe> [-slow_asserts] <Tool name>\n", argv[0]);
|
|
return 1;
|
|
}
|
|
|
|
FILE_NAME = argv[1];
|
|
|
|
if (0 != pipe(syncPipe))
|
|
{
|
|
perror("pipe");
|
|
return 1;
|
|
}
|
|
pid_t pid = fork();
|
|
BlockUserSignals();
|
|
|
|
if (0 != pid)
|
|
{
|
|
// In the parent process.
|
|
close(syncPipe[0]); // close the read side of the pipe
|
|
mutex_lock_check_errno(&mutex);
|
|
mutex_lock_check_errno(&mutex1);
|
|
/*
|
|
* create two threads, one which sends signals to the other threads, which receives them.
|
|
*/
|
|
pthread_create(&one_tid, NULL, SignalSender, NULL);
|
|
pthread_create(&two_tid, NULL, SignalReceiver, NULL);
|
|
|
|
/*
|
|
* suspended execution until the two threads terminate
|
|
*/
|
|
pthread_join(two_tid,NULL);
|
|
mutex_unlock_check_errno(&mutex); // release mutex as one_tid may wait on it
|
|
pthread_join(one_tid, NULL);
|
|
}
|
|
else
|
|
{
|
|
// In the child process.
|
|
char dummy;
|
|
close(syncPipe[1]); // close the write side of the pipe
|
|
read(syncPipe[0], &dummy, sizeof(dummy)); // wait for parent
|
|
close(syncPipe[0]); // close the read side as we're done
|
|
char attachPid[MAX_SIZE];
|
|
sprintf(attachPid, "%d", parentPid);
|
|
|
|
const char* args[9];
|
|
int argsco = 0;
|
|
int argsci = 2; // input argument #2 is the Pin executable (see documentation at the top of the main function)
|
|
args[argsco++] = argv[argsci++]; // pin executable
|
|
if (argc == 5)
|
|
{
|
|
const char* slow_assert = args[argsco++] = argv[argsci++]; // -slow_asserts (if present)
|
|
}
|
|
args[argsco++] = "-probe";
|
|
args[argsco++] = "-pid";
|
|
args[argsco++] = attachPid;
|
|
args[argsco++] = "-t";
|
|
args[argsco++] = argv[argsci++]; // tool name
|
|
args[argsco++] = NULL; // end
|
|
|
|
/*
|
|
* Pin attach to the parent thread.
|
|
* never return
|
|
*/
|
|
execv(args[0], (char * const *)args);
|
|
perror("execv");
|
|
return 10;
|
|
}
|
|
return 0;
|
|
}
|