mirror of
git://git.code.sf.net/p/sbcl/sbcl
synced 2026-09-10 07:26:40 -04:00
163 lines
4.3 KiB
C
163 lines
4.3 KiB
C
/* In as much as this file simulates "foreign" code,
|
|
* we don't include "genesis/sbcl.h" and we use the native thread API
|
|
* for the platform */
|
|
|
|
#ifdef _WIN32
|
|
# include <handleapi.h>
|
|
# include <process.h>
|
|
# include <processthreadsapi.h>
|
|
# include <synchapi.h> // for WaitForSingleObject
|
|
#else
|
|
# include <pthread.h>
|
|
#endif
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
struct thread_arg { void * funkyfun; int index; int n_calls; };
|
|
|
|
char *salutations[8] = {
|
|
"Hello", "Hi there!", "Hey", "Hi!", "Ahoy there", "What's up!", "Hola",
|
|
"That's a winner"
|
|
};
|
|
int sharedvar;
|
|
|
|
#ifdef _WIN32
|
|
__stdcall unsigned int perftest_thread(LPVOID void_arg)
|
|
#else
|
|
void* perftest_thread(void* void_arg)
|
|
#endif
|
|
{
|
|
struct thread_arg* arg = void_arg;
|
|
int (*lispfun)() = arg->funkyfun;
|
|
int ncalls = arg->n_calls;
|
|
int i;
|
|
for (i=0; i<ncalls; ++i) lispfun();
|
|
return 0;
|
|
}
|
|
|
|
int minimal_perftest(void* ptr, int n_calls)
|
|
{
|
|
struct thread_arg arg;
|
|
arg.funkyfun = ptr;
|
|
arg.n_calls = n_calls;
|
|
#ifdef _WIN32
|
|
HANDLE thr;
|
|
thr = (HANDLE)_beginthreadex(NULL, 0, perftest_thread, &arg, 0, NULL);
|
|
WaitForSingleObject(thr,0xffffffff);
|
|
CloseHandle(thr);
|
|
#else
|
|
pthread_t thr;
|
|
pthread_create(&thr, 0, perftest_thread, &arg);
|
|
pthread_join(thr,0);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
void*
|
|
#ifdef _WIN32
|
|
__stdcall
|
|
#endif
|
|
doThatThing(void* void_arg)
|
|
{
|
|
struct thread_arg* arg = void_arg;
|
|
int thread_result = 0xC0FEFE;
|
|
int (*lispfun)(char*,double) = arg->funkyfun;
|
|
int i;
|
|
// fprintf(stderr, "enter doThatThing %p\n", void_arg); fflush(stderr);
|
|
for(i=0; i<arg->n_calls; ++i) {
|
|
int index = __sync_fetch_and_add(&sharedvar,1);
|
|
char *salutation = salutations[index % 8];
|
|
int answer = lispfun(salutation, arg->index + i);
|
|
if (answer != (arg->index + i) * strlen(salutation)) thread_result = 0;
|
|
}
|
|
return (void*)(uintptr_t)thread_result;
|
|
}
|
|
|
|
int call_thing_from_threads(void* ptr, int n_threads, int n_calls)
|
|
{
|
|
struct {
|
|
#ifdef _WIN32
|
|
HANDLE handle;
|
|
DWORD result;
|
|
#else
|
|
pthread_t pthread_id;
|
|
void* result;
|
|
#endif
|
|
struct thread_arg arg;
|
|
} threads[50];
|
|
if (n_threads>50) {
|
|
fprintf(stderr, "pick a smaller number\n");
|
|
return -1;
|
|
}
|
|
int i;
|
|
for(i=0; i<n_threads; ++i) {
|
|
threads[i].arg.funkyfun = ptr;
|
|
threads[i].arg.index = i + 1;
|
|
threads[i].arg.n_calls = n_calls;
|
|
#ifdef _WIN32
|
|
threads[i].handle = (HANDLE)_beginthreadex(NULL, 0, (unsigned int (*)(void *))doThatThing, &threads[i].arg, 0, NULL);
|
|
#else
|
|
pthread_create(&threads[i].pthread_id, 0, doThatThing, &threads[i].arg);
|
|
#endif
|
|
}
|
|
int all_ok = 1;
|
|
for(i=0; i<n_threads; ++i) {
|
|
#ifdef _WIN32
|
|
DWORD result;
|
|
// I don't know which header file defines INFINITE (for the timeout)
|
|
// so any large value should do.
|
|
result = WaitForSingleObject(threads[i].handle, 0xffffffff);
|
|
GetExitCodeThread(threads[i].handle, &threads[i].result);
|
|
CloseHandle(threads[i].handle);
|
|
if (threads[i].result != 0xC0FEFE) all_ok = 0;
|
|
#else
|
|
pthread_join(threads[i].pthread_id, &threads[i].result);
|
|
#if 0
|
|
fprintf(stderr, "%d: pthread %lx returned %p\n",
|
|
i, (long)threads[i].pthread_id, threads[i].result);
|
|
#endif
|
|
if ((uintptr_t)threads[i].result != 0xC0FEFE) all_ok = 0;
|
|
#endif
|
|
}
|
|
return all_ok;
|
|
}
|
|
|
|
/// The code following is for the no-lockup-on-exit test, unrelated to the above
|
|
/// FIXME: implement a watchdog timer for win32
|
|
#ifndef _WIN32
|
|
#include <signal.h>
|
|
#include <sys/time.h>
|
|
#include <unistd.h>
|
|
|
|
static pthread_mutex_t some_global_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
void acquire_a_global_lock() {
|
|
pthread_mutex_lock(&some_global_lock);
|
|
}
|
|
void release_a_global_lock() {
|
|
pthread_mutex_unlock(&some_global_lock);
|
|
}
|
|
static void alarmclock_expired(int sig)
|
|
{
|
|
char msg[] = "timed out\n";
|
|
write(2, msg, sizeof msg-1);
|
|
_exit(1);
|
|
}
|
|
|
|
/// Exit with failure if we can't exit within a set time.
|
|
void prepare_exit_test(int seconds)
|
|
{
|
|
struct sigaction sa;
|
|
sa.sa_handler = alarmclock_expired;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = 0;
|
|
sigaction(SIGALRM, &sa, 0);
|
|
struct itimerval it;
|
|
it.it_value.tv_sec = seconds;
|
|
it.it_value.tv_usec = 0;
|
|
it.it_interval.tv_sec = it.it_interval.tv_usec = 0;
|
|
setitimer(ITIMER_REAL, &it, 0);
|
|
}
|
|
#endif
|