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.
216 lines
5.6 KiB
216 lines
5.6 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 is a stress test for handling signals in a multi-threaded application.
|
|
* The root thread creates two classes of worker threads: computers and blockers.
|
|
* Computers execute a small loop that should run entirely from the Pin code cache
|
|
* once it is compiled. Blockers iteratively execute a blocking system call. The
|
|
* root thread randomly sends signals to each of the works as fast as possible.
|
|
*/
|
|
|
|
#include <cstdlib>
|
|
#include <iostream>
|
|
#include <pthread.h>
|
|
#include <cassert>
|
|
#include <signal.h>
|
|
#include <time.h>
|
|
|
|
|
|
const unsigned NUM_BLOCKERS = 8;
|
|
const unsigned NUM_COMPUTERS = 8;
|
|
const unsigned NUM_SIGNALS = 1000;
|
|
|
|
|
|
// The total number of signals received by all threads.
|
|
//
|
|
volatile unsigned NumSignalsReceived = 0;
|
|
pthread_mutex_t SignalReceivedLock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
// Information for each worker thread.
|
|
//
|
|
struct THREAD_INFO
|
|
{
|
|
THREAD_INFO() : _ready(false)
|
|
{
|
|
pthread_mutex_init(&_readyLock, 0);
|
|
pthread_cond_init(&_readyCond, 0);
|
|
}
|
|
|
|
~THREAD_INFO()
|
|
{
|
|
pthread_cond_destroy(&_readyCond);
|
|
pthread_mutex_destroy(&_readyLock);
|
|
}
|
|
|
|
pthread_t _tid;
|
|
|
|
// This is set TRUE when the thread is ready to receive a signal.
|
|
//
|
|
bool _ready;
|
|
pthread_mutex_t _readyLock;
|
|
pthread_cond_t _readyCond;
|
|
};
|
|
|
|
THREAD_INFO *ThreadInfos;
|
|
|
|
// Each thread uses this key to find its own THREAD_INFO.
|
|
//
|
|
pthread_key_t MyInfoKey;
|
|
|
|
|
|
static void *BlockerRoot(void *);
|
|
static void *ComputerRoot(void *);
|
|
static void SetMyInfo(THREAD_INFO *);
|
|
static void Handle(int);
|
|
|
|
|
|
int main()
|
|
{
|
|
struct sigaction act;
|
|
act.sa_handler = Handle;
|
|
act.sa_flags = 0;
|
|
sigemptyset(&act.sa_mask);
|
|
if (sigaction(SIGUSR1, &act, 0) != 0)
|
|
{
|
|
std::cerr << "Unable to set SIGUSR1 handler\n";
|
|
return 1;
|
|
}
|
|
|
|
if (pthread_key_create(&MyInfoKey, 0) != 0)
|
|
{
|
|
std::cerr << "Unable to create key\n";
|
|
return 1;
|
|
}
|
|
|
|
// Create the worker threads.
|
|
//
|
|
ThreadInfos = new THREAD_INFO[NUM_BLOCKERS + NUM_COMPUTERS];
|
|
for (unsigned i = 0; i < NUM_BLOCKERS; i++)
|
|
{
|
|
THREAD_INFO *info = &ThreadInfos[i];
|
|
if (pthread_create(&info->_tid, 0, BlockerRoot, info) != 0)
|
|
{
|
|
std::cerr << "Unable to create blocker thread\n";
|
|
return 1;
|
|
}
|
|
}
|
|
for (unsigned i = 0; i < NUM_COMPUTERS; i++)
|
|
{
|
|
THREAD_INFO *info = &ThreadInfos[NUM_BLOCKERS + i];
|
|
if (pthread_create(&info->_tid, 0, ComputerRoot, info) != 0)
|
|
{
|
|
std::cerr << "Unable to create computer thread\n";
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Randomly send signals to the workers.
|
|
//
|
|
for (unsigned i = 0; i < NUM_SIGNALS; i++)
|
|
{
|
|
unsigned index = std::rand() % (NUM_BLOCKERS + NUM_COMPUTERS);
|
|
THREAD_INFO *info = &ThreadInfos[index];
|
|
|
|
// Wait for the worker to be ready to handle a signal.
|
|
//
|
|
pthread_mutex_lock(&info->_readyLock);
|
|
while (!info->_ready)
|
|
pthread_cond_wait(&info->_readyCond, &info->_readyLock);
|
|
info->_ready = false;
|
|
pthread_mutex_unlock(&info->_readyLock);
|
|
|
|
std::cout << "Sending signal " << std::dec << i << "\n";
|
|
if (pthread_kill(info->_tid, SIGUSR1) != 0)
|
|
{
|
|
std::cerr << "Unable to send SIGUSR1 to thread index " << std::dec << index << "\n";
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Wait for all the workers to terminate.
|
|
//
|
|
for (unsigned i = 0; i < NUM_BLOCKERS + NUM_COMPUTERS; i++)
|
|
{
|
|
if (pthread_join(ThreadInfos[i]._tid, 0) != 0)
|
|
{
|
|
std::cerr << "Unable to wait for thread index " << std::dec << i << "\n";
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
delete [] ThreadInfos;
|
|
pthread_key_delete(MyInfoKey);
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void *BlockerRoot(void *vinfo)
|
|
{
|
|
SetMyInfo(static_cast<THREAD_INFO *>(vinfo));
|
|
|
|
while (NumSignalsReceived < NUM_SIGNALS)
|
|
{
|
|
struct timespec tv;
|
|
tv.tv_sec = 10;
|
|
tv.tv_nsec = 0;
|
|
nanosleep(&tv, 0);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void *ComputerRoot(void *vinfo)
|
|
{
|
|
SetMyInfo(static_cast<THREAD_INFO *>(vinfo));
|
|
|
|
volatile double x[100];
|
|
while (NumSignalsReceived < NUM_SIGNALS)
|
|
{
|
|
for (unsigned i = 0; i < 100; i++)
|
|
x[i] = (double)(i+1);
|
|
for (unsigned i = 2; i < 100; i++)
|
|
x[i] = x[i] / x[i-1] * x[i-2] + x[i];
|
|
}
|
|
}
|
|
|
|
|
|
static void SetMyInfo(THREAD_INFO *info)
|
|
{
|
|
// Initialize the worker's thread-private data to point to it's THREAD_INFO.
|
|
// Once we do this, we are ready to handle a signal.
|
|
//
|
|
pthread_mutex_lock(&info->_readyLock);
|
|
pthread_setspecific(MyInfoKey, info);
|
|
info->_ready = true;
|
|
pthread_cond_signal(&info->_readyCond);
|
|
pthread_mutex_unlock(&info->_readyLock);
|
|
}
|
|
|
|
|
|
static void Handle(int)
|
|
{
|
|
// Count this signal.
|
|
//
|
|
pthread_mutex_lock(&SignalReceivedLock);
|
|
NumSignalsReceived++;
|
|
pthread_mutex_unlock(&SignalReceivedLock);
|
|
|
|
// Once we count the signal, this thread is ready to handle another signal.
|
|
//
|
|
THREAD_INFO *info = static_cast<THREAD_INFO *>(pthread_getspecific(MyInfoKey));
|
|
pthread_mutex_lock(&info->_readyLock);
|
|
assert(!info->_ready);
|
|
info->_ready = true;
|
|
pthread_cond_signal(&info->_readyCond);
|
|
pthread_mutex_unlock(&info->_readyLock);
|
|
}
|