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.
173 lines
5.1 KiB
173 lines
5.1 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.
|
|
*/
|
|
|
|
/*!
|
|
* The purpose of this application, combined with the tool: "syscalls_and_locks_tool", is to check the correctness of the
|
|
* lock acquisition algorithm enhancement, which designed to be clone-proof for probe mode
|
|
*
|
|
* This application verifies that a deadlock won't be encountered when the application calls to clone directly/indirectly,
|
|
* while a different thread (in a different/same process) holds the lock (PIN_LOCK/PIN_RWMUTEX/client lock).
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <pthread.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
|
|
#define TIMEOUT 120
|
|
|
|
#define STACK_SIZE (1024 * 1024) /* Stack size for cloned child */
|
|
#include <sys/syscall.h>
|
|
|
|
volatile bool thread1Init = false;
|
|
|
|
int syscall_type;
|
|
|
|
enum ExitType {
|
|
RES_SUCCESS = 0, // 1
|
|
RES_ALARM_TIMEOUT, // 2
|
|
RES_MALLOC_FAILED, // 3
|
|
RES_RES_INVALID_ARGS // 4
|
|
};
|
|
|
|
// Pin doesn't kill the process if the application encounters a deadlock, exit on SIGALRM.
|
|
void ExitOnAlarm(int sig)
|
|
{
|
|
fprintf(stderr, "Timeout has passed, stuck in the system function library call, exit on SIGALRM\n");
|
|
exit(RES_ALARM_TIMEOUT);
|
|
}
|
|
|
|
// The tool puts an analysis routine on this function to notify t1
|
|
// when the lock has been acquired.
|
|
extern "C" void WaitThread2AcquireLock()
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
// The tool sets an analysis function here to notify t1 when t2
|
|
// has acquired and released the lock.
|
|
extern "C" void WaitUntilLockAcquiredAndReleased()
|
|
{
|
|
// Do nothing
|
|
}
|
|
|
|
// When the child process is created with clone(), it executes this function.
|
|
int childFunc(void * arg)
|
|
{
|
|
// Do nothing
|
|
return 0;
|
|
}
|
|
|
|
void * thread_func1(void *arg)
|
|
{
|
|
// Notify t2 that the lock should be acquired.
|
|
thread1Init = true;
|
|
|
|
// The tool puts an analysis routine on this function to notify t1
|
|
// when the lock has been acquired.
|
|
WaitThread2AcquireLock();
|
|
|
|
// If syscall_type equals 1, the system function will be called
|
|
// During this function call, the clone system call is called. We want to verify that
|
|
// a deadlock won't be encountered while the lock is by t2.
|
|
if(syscall_type == 1)
|
|
{
|
|
system("/bin/ls");
|
|
}
|
|
|
|
// If syscall_type equals 2 the popen function will be called. This function opens a process by creating a pipe,
|
|
// forking and invoking a the shell. We want to verify that a deadlock won't be encounter when this function is being
|
|
// called while the lock is held by t2.
|
|
else if(syscall_type == 2)
|
|
{
|
|
FILE* pipe = popen("uname -r", "r");
|
|
pclose(pipe);
|
|
}
|
|
|
|
// If syscall_type equals 3, the new thread will be created in a new thread group.
|
|
// If syscall_type equals 4, the new thread will be in the same thread group as the caller and will share its
|
|
// virtual memory.
|
|
// We want to verify, in both of these scenarios, that a deadlock won't be encountered when the clone system call
|
|
// is being called while the lock is held by t2.
|
|
else if (syscall_type == 3 || syscall_type == 4)
|
|
{
|
|
char *stack;
|
|
char *stackTop;
|
|
stack = (char *)malloc(STACK_SIZE);
|
|
if (stack == NULL) exit(RES_MALLOC_FAILED);
|
|
stackTop = stack + STACK_SIZE;
|
|
|
|
if (3 == syscall_type)
|
|
{
|
|
clone(childFunc, stackTop, 0 , 0);
|
|
}
|
|
else if (4 == syscall_type)
|
|
{
|
|
clone(childFunc, stackTop, CLONE_VM | CLONE_SIGHAND | CLONE_THREAD, 0);
|
|
}
|
|
|
|
// Sleep for 30 seconds to increase the probability that the new process which has been created by clone
|
|
// will finish its execution.
|
|
sleep(30);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void * thread_func2 (void *arg)
|
|
{
|
|
// Wait until t1 starts to run.
|
|
while(!thread1Init) sched_yield();
|
|
|
|
// Wait until the lock is acquired and released.
|
|
WaitUntilLockAcquiredAndReleased();
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Expected argv arguments:
|
|
// [1] syscall type
|
|
// 1 - execute the system function.
|
|
// 2 - execute the popen function.
|
|
// 3 - execute the clone system call where the parent of the new child will be different
|
|
// from that of the calling process.
|
|
// 4 - execute the clone system call where the parent of the new child will be the same as
|
|
// that of the calling process.
|
|
int main (int argc, char *argv[])
|
|
{
|
|
if(argc!=2)
|
|
{
|
|
fflush(stderr);
|
|
exit(RES_RES_INVALID_ARGS);
|
|
}
|
|
|
|
syscall_type = atoi(argv[1]);
|
|
|
|
pthread_t t1;
|
|
pthread_t t2;
|
|
|
|
pthread_create (&t1, 0, thread_func1, 0);
|
|
pthread_create (&t2, 0, thread_func2, 0);
|
|
|
|
//Exit in 120 sec
|
|
signal(SIGALRM, ExitOnAlarm);
|
|
alarm(TIMEOUT);
|
|
|
|
pthread_join (t1, 0);
|
|
pthread_join (t2, 0);
|
|
|
|
printf("All threads exited. The test PASSED\n");
|
|
return RES_SUCCESS;
|
|
}
|
|
|