Skip to content

Instantly share code, notes, and snippets.

@mmalone

mmalone/build.sh Secret

Created January 25, 2011 07:22
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mmalone/2d2b78987ea451c2edd6 to your computer and use it in GitHub Desktop.
Save mmalone/2d2b78987ea451c2edd6 to your computer and use it in GitHub Desktop.
gcc -lpthread -lrt -std=gnu99 -o libctest libctest.c
/* This makes EC2 unhappy. */
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <time.h>
#include <pthread.h>
#define TEST_CLOCK CLOCK_PROCESS_CPUTIME_ID
/* This function is intended to rack up both user and system time. */
static void * chew_cpu (void *arg) {
while (1) {
static volatile char buf[4096];
for (int i = 0; i < 100; ++i) {
for (size_t j = 0; j < sizeof buf; ++j) {
buf[j] = 0xaa;
}
}
int nullfd = open("/dev/null", O_WRONLY);
for(int i = 0; i < 100; ++i) {
for (size_t j = 0; j < sizeof buf; ++j) {
buf[j] = 0xbb;
}
}
write(nullfd, (char *) buf, sizeof buf);
close(nullfd);
}
return NULL;
}
int doit_hansel() {
/* Test timers on our own process CPU clock by having a worker thread
eating CPU. First make sure we can make such timers at all. */
timer_t t;
if (timer_create(TEST_CLOCK, NULL, &t) != 0) {
printf ("timer_create: %m\n");
return 1;
}
timer_delete(t);
pthread_t th;
int e = pthread_create(&th, NULL, chew_cpu, NULL);
if (e != 0) {
printf("pthread_create: %s\n", strerror(e));
exit (1);
}
printf("success.\n");
return 0;
}
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
timer_t timer_none, timer_sig1, timer_sig2, timer_thr1, timer_thr2;
int thr1_cnt, thr1_err;
union sigval thr1_sigval;
struct timespec thr1_ts;
static void thr1 (union sigval sigval) {
pthread_mutex_lock (&lock);
thr1_err = clock_gettime (TEST_CLOCK, &thr1_ts);
if (thr1_cnt >= 5)
{
struct itimerspec it = { };
thr1_err |= timer_settime (timer_thr1, 0, &it, NULL);
}
thr1_sigval = sigval;
++thr1_cnt;
pthread_cond_signal (&cond);
pthread_mutex_unlock (&lock);
}
int thr2_cnt, thr2_err;
union sigval thr2_sigval;
size_t thr2_guardsize;
struct timespec thr2_ts;
static void thr2 (union sigval sigval) {
pthread_attr_t nattr;
int err = 0;
size_t guardsize = -1;
int ret = pthread_getattr_np (pthread_self (), &nattr);
if (ret)
{
errno = ret;
printf ("*** pthread_getattr_np failed: %m\n");
err = 1;
}
else
{
ret = pthread_attr_getguardsize (&nattr, &guardsize);
if (ret)
{
errno = ret;
printf ("*** pthread_attr_getguardsize failed: %m\n");
err = 1;
}
if (pthread_attr_destroy (&nattr) != 0)
{
puts ("*** pthread_attr_destroy failed");
err = 1;
}
}
pthread_mutex_lock (&lock);
thr2_err = clock_gettime (TEST_CLOCK, &thr2_ts) | err;
if (thr2_cnt >= 5)
{
struct itimerspec it = { };
thr2_err |= timer_settime (timer_thr2, 0, &it, NULL);
}
thr2_sigval = sigval;
++thr2_cnt;
thr2_guardsize = guardsize;
pthread_cond_signal (&cond);
pthread_mutex_unlock (&lock);
}
volatile int sig1_cnt, sig1_err;
volatile union sigval sig1_sigval;
struct timespec sig1_ts;
static void
sig1_handler (int sig, siginfo_t *info, void *ctx)
{
int err = 0;
if (sig != SIGRTMIN) err |= 1 << 0;
if (info->si_signo != SIGRTMIN) err |= 1 << 1;
if (info->si_code != SI_TIMER) err |= 1 << 2;
if (clock_gettime (TEST_CLOCK, &sig1_ts) != 0)
err |= 1 << 3;
if (sig1_cnt >= 5)
{
struct itimerspec it = { };
if (timer_settime (timer_sig1, 0, &it, NULL))
err |= 1 << 4;
}
sig1_err |= err;
sig1_sigval = info->si_value;
++sig1_cnt;
}
volatile int sig2_cnt, sig2_err;
volatile union sigval sig2_sigval;
struct timespec sig2_ts;
static void
sig2_handler (int sig, siginfo_t *info, void *ctx)
{
int err = 0;
if (sig != SIGRTMIN + 1) err |= 1 << 0;
if (info->si_signo != SIGRTMIN + 1) err |= 1 << 1;
if (info->si_code != SI_TIMER) err |= 1 << 2;
if (clock_gettime (TEST_CLOCK, &sig2_ts) != 0)
err |= 1 << 3;
if (sig2_cnt >= 5)
{
struct itimerspec it = { };
if (timer_settime (timer_sig2, 0, &it, NULL))
err |= 1 << 4;
}
sig2_err |= err;
sig2_sigval = info->si_value;
++sig2_cnt;
}
/* Check if end is later or equal to start + nsec. */
static int
check_ts (const char *name, const struct timespec *start,
const struct timespec *end, long msec)
{
struct timespec ts = *start;
ts.tv_sec += msec / 1000000;
ts.tv_nsec += (msec % 1000000) * 1000;
if (ts.tv_nsec >= 1000000000)
{
++ts.tv_sec;
ts.tv_nsec -= 1000000000;
}
if (end->tv_sec < ts.tv_sec
|| (end->tv_sec == ts.tv_sec && end->tv_nsec < ts.tv_nsec))
{
printf ("\
*** timer %s invoked too soon: %ld.%09ld instead of expected %ld.%09ld\n",
name, (long) end->tv_sec, end->tv_nsec,
(long) ts.tv_sec, ts.tv_nsec);
return 1;
}
else
return 0;
}
# define TEMP_FAILURE_RETRY(expression) \
(__extension__ \
({ long int __result; \
do __result = (long int) (expression); \
while (__result == -1L && errno == EINTR); \
__result; }))
int main (int argc, char *argv[]) {
int result = 0;
doit_hansel();
struct timespec ts;
if (clock_gettime (TEST_CLOCK, &ts) != 0)
{
printf ("*** clock_gettime failed: %m\n");
result = 1;
}
else
printf ("clock_gettime returned timespec = { %ld, %ld }\n",
(long) ts.tv_sec, ts.tv_nsec);
if (clock_getres (TEST_CLOCK, &ts) != 0)
{
printf ("*** clock_getres failed: %m\n");
result = 1;
}
else
printf ("clock_getres returned timespec = { %ld, %ld }\n",
(long) ts.tv_sec, ts.tv_nsec);
struct sigevent ev;
memset (&ev, 0x11, sizeof (ev));
ev.sigev_notify = SIGEV_NONE;
if (timer_create (TEST_CLOCK, &ev, &timer_none) != 0)
{
printf ("*** timer_create for timer_none failed: %m\n");
return 1;
}
struct sigaction sa = { .sa_sigaction = sig1_handler,
.sa_flags = SA_SIGINFO };
sigemptyset (&sa.sa_mask);
sigaction (SIGRTMIN, &sa, NULL);
sa.sa_sigaction = sig2_handler;
sigaction (SIGRTMIN + 1, &sa, NULL);
memset (&ev, 0x22, sizeof (ev));
ev.sigev_notify = SIGEV_SIGNAL;
ev.sigev_signo = SIGRTMIN;
ev.sigev_value.sival_ptr = &ev;
if (timer_create (TEST_CLOCK, &ev, &timer_sig1) != 0)
{
printf ("*** timer_create for timer_sig1 failed: %m\n");
return 1;
}
memset (&ev, 0x33, sizeof (ev));
ev.sigev_notify = SIGEV_SIGNAL;
ev.sigev_signo = SIGRTMIN + 1;
ev.sigev_value.sival_int = 163;
if (timer_create (TEST_CLOCK, &ev, &timer_sig2) != 0)
{
printf ("*** timer_create for timer_sig2 failed: %m\n");
return 1;
}
memset (&ev, 0x44, sizeof (ev));
ev.sigev_notify = SIGEV_THREAD;
ev.sigev_notify_function = thr1;
ev.sigev_notify_attributes = NULL;
ev.sigev_value.sival_ptr = &ev;
if (timer_create (TEST_CLOCK, &ev, &timer_thr1) != 0)
{
printf ("*** timer_create for timer_thr1 failed: %m\n");
return 1;
}
pthread_attr_t nattr;
if (pthread_attr_init (&nattr)
|| pthread_attr_setguardsize (&nattr, 0))
{
puts ("*** pthread_attr_t setup failed");
result = 1;
}
memset (&ev, 0x55, sizeof (ev));
ev.sigev_notify = SIGEV_THREAD;
ev.sigev_notify_function = thr2;
ev.sigev_notify_attributes = &nattr;
ev.sigev_value.sival_int = 111;
if (timer_create (TEST_CLOCK, &ev, &timer_thr2) != 0)
{
printf ("*** timer_create for timer_thr2 failed: %m\n");
return 1;
}
int ret = timer_getoverrun (timer_thr1);
if (ret != 0)
{
if (ret == -1)
printf ("*** timer_getoverrun failed: %m\n");
else
printf ("*** timer_getoverrun returned %d != 0\n", ret);
result = 1;
}
struct itimerspec it;
it.it_value.tv_sec = 0;
it.it_value.tv_nsec = -26;
it.it_interval.tv_sec = 0;
it.it_interval.tv_nsec = 0;
if (timer_settime (timer_sig1, 0, &it, NULL) == 0)
{
puts ("*** timer_settime with negative tv_nsec unexpectedly succeeded");
result = 1;
}
else if (errno != EINVAL)
{
printf ("*** timer_settime with negative tv_nsec did not fail with "
"EINVAL: %m\n");
result = 1;
}
it.it_value.tv_nsec = 100000;
it.it_interval.tv_nsec = 1000000000;
if (timer_settime (timer_sig2, 0, &it, NULL) == 0)
{
puts ("\
*** timer_settime with tv_nsec 1000000000 unexpectedly succeeded");
result = 1;
}
else if (errno != EINVAL)
{
printf ("*** timer_settime with tv_nsec 1000000000 did not fail with "
"EINVAL: %m\n");
result = 1;
}
struct timespec startts;
if (clock_gettime (TEST_CLOCK, &startts) != 0)
{
printf ("*** clock_gettime failed: %m\n");
result = 1;
}
it.it_value.tv_nsec = 100000000;
it.it_interval.tv_nsec = 0;
if (timer_settime (timer_none, 0, &it, NULL) != 0)
{
printf ("*** timer_settime timer_none failed: %m\n");
result = 1;
}
it.it_value.tv_nsec = 200000000;
if (timer_settime (timer_thr1, 0, &it, NULL) != 0)
{
printf ("*** timer_settime timer_thr1 failed: %m\n");
result = 1;
}
it.it_value.tv_nsec = 300000000;
if (timer_settime (timer_thr2, 0, &it, NULL) != 0)
{
printf ("*** timer_settime timer_thr2 failed: %m\n");
result = 1;
}
it.it_value.tv_nsec = 400000000;
if (timer_settime (timer_sig1, 0, &it, NULL) != 0)
{
printf ("*** timer_settime timer_sig1 failed: %m\n");
result = 1;
}
it.it_value.tv_nsec = 500000000;
if (TEMP_FAILURE_RETRY (timer_settime (timer_sig2, 0, &it, NULL)) != 0)
{
printf ("*** timer_settime timer_sig2 failed: %m\n");
result = 1;
}
pthread_mutex_lock (&lock);
while (thr1_cnt == 0 || thr2_cnt == 0)
pthread_cond_wait (&cond, &lock);
pthread_mutex_unlock (&lock);
while (sig1_cnt == 0 || sig2_cnt == 0)
{
ts.tv_sec = 0;
ts.tv_nsec = 100000000;
nanosleep (&ts, NULL);
}
pthread_mutex_lock (&lock);
if (thr1_cnt != 1)
{
printf ("*** thr1 not called exactly once, but %d times\n", thr1_cnt);
result = 1;
}
else if (thr1_err)
{
puts ("*** an error occurred in thr1");
result = 1;
}
else if (thr1_sigval.sival_ptr != &ev)
{
printf ("*** thr1_sigval.sival_ptr %p != %p\n",
thr1_sigval.sival_ptr, &ev);
result = 1;
}
else if (check_ts ("thr1", &startts, &thr1_ts, 200000))
result = 1;
if (thr2_cnt != 1)
{
printf ("*** thr2 not called exactly once, but %d times\n", thr2_cnt);
result = 1;
}
else if (thr2_err)
{
puts ("*** an error occurred in thr2");
result = 1;
}
else if (thr2_sigval.sival_int != 111)
{
printf ("*** thr2_sigval.sival_ptr %d != 111\n", thr2_sigval.sival_int);
result = 1;
}
else if (check_ts ("thr2", &startts, &thr2_ts, 300000))
result = 1;
else if (thr2_guardsize != 0)
{
printf ("*** thr2 guardsize %zd != 0\n", thr2_guardsize);
result = 1;
}
pthread_mutex_unlock (&lock);
if (sig1_cnt != 1)
{
printf ("*** sig1 not called exactly once, but %d times\n", sig1_cnt);
result = 1;
}
else if (sig1_err)
{
printf ("*** errors occurred in sig1 handler %x\n", sig1_err);
result = 1;
}
else if (sig1_sigval.sival_ptr != &ev)
{
printf ("*** sig1_sigval.sival_ptr %p != %p\n",
sig1_sigval.sival_ptr, &ev);
result = 1;
}
else if (check_ts ("sig1", &startts, &sig1_ts, 400000))
result = 1;
if (sig2_cnt != 1)
{
printf ("*** sig2 not called exactly once, but %d times\n", sig2_cnt);
result = 1;
}
else if (sig2_err)
{
printf ("*** errors occurred in sig2 handler %x\n", sig2_err);
result = 1;
}
else if (sig2_sigval.sival_int != 163)
{
printf ("*** sig2_sigval.sival_ptr %d != 163\n", sig2_sigval.sival_int);
result = 1;
}
else if (check_ts ("sig2", &startts, &sig2_ts, 500000))
result = 1;
if (timer_gettime (timer_none, &it) != 0)
{
printf ("*** timer_gettime timer_none failed: %m\n");
result = 1;
}
else if (it.it_value.tv_sec || it.it_value.tv_nsec
|| it.it_interval.tv_sec || it.it_interval.tv_nsec)
{
printf ("\
*** timer_gettime timer_none returned { %ld.%09ld, %ld.%09ld }\n",
(long) it.it_value.tv_sec, it.it_value.tv_nsec,
(long) it.it_interval.tv_sec, it.it_interval.tv_nsec);
result = 1;
}
if (clock_gettime (TEST_CLOCK, &startts) != 0)
{
printf ("*** clock_gettime failed: %m\n");
result = 1;
}
it.it_value.tv_sec = 1;
it.it_value.tv_nsec = 0;
it.it_interval.tv_sec = 0;
it.it_interval.tv_nsec = 100000000;
if (timer_settime (timer_none, 0, &it, NULL) != 0)
{
printf ("*** timer_settime timer_none failed: %m\n");
result = 1;
}
it.it_value.tv_nsec = 100000000;
it.it_interval.tv_nsec = 200000000;
if (timer_settime (timer_thr1, 0, &it, NULL) != 0)
{
printf ("*** timer_settime timer_thr1 failed: %m\n");
result = 1;
}
it.it_value.tv_nsec = 200000000;
it.it_interval.tv_nsec = 300000000;
if (timer_settime (timer_thr2, 0, &it, NULL) != 0)
{
printf ("*** timer_settime timer_thr2 failed: %m\n");
result = 1;
}
it.it_value.tv_nsec = 300000000;
it.it_interval.tv_nsec = 400000000;
if (timer_settime (timer_sig1, 0, &it, NULL) != 0)
{
printf ("*** timer_settime timer_sig1 failed: %m\n");
result = 1;
}
it.it_value.tv_nsec = 400000000;
it.it_interval.tv_nsec = 500000000;
if (TEMP_FAILURE_RETRY (timer_settime (timer_sig2, 0, &it, NULL)) != 0)
{
printf ("*** timer_settime timer_sig2 failed: %m\n");
result = 1;
}
pthread_mutex_lock (&lock);
while (thr1_cnt < 6 || thr2_cnt < 6)
pthread_cond_wait (&cond, &lock);
pthread_mutex_unlock (&lock);
while (sig1_cnt < 6 || sig2_cnt < 6)
{
ts.tv_sec = 0;
ts.tv_nsec = 100000000;
nanosleep (&ts, NULL);
}
pthread_mutex_lock (&lock);
if (thr1_err)
{
puts ("*** an error occurred in thr1");
result = 1;
}
else if (check_ts ("thr1", &startts, &thr1_ts, 1100000 + 4 * 200000))
result = 1;
if (thr2_err)
{
puts ("*** an error occurred in thr2");
result = 1;
}
else if (check_ts ("thr2", &startts, &thr2_ts, 1200000 + 4 * 300000))
result = 1;
else if (thr2_guardsize != 0)
{
printf ("*** thr2 guardsize %zd != 0\n", thr2_guardsize);
result = 1;
}
pthread_mutex_unlock (&lock);
if (sig1_err)
{
printf ("*** errors occurred in sig1 handler %x\n", sig1_err);
result = 1;
}
else if (check_ts ("sig1", &startts, &sig1_ts, 1300000 + 4 * 400000))
result = 1;
if (sig2_err)
{
printf ("*** errors occurred in sig2 handler %x\n", sig2_err);
result = 1;
}
else if (check_ts ("sig2", &startts, &sig2_ts, 1400000 + 4 * 500000))
result = 1;
if (timer_gettime (timer_none, &it) != 0)
{
printf ("*** timer_gettime timer_none failed: %m\n");
result = 1;
}
else if (it.it_interval.tv_sec || it.it_interval.tv_nsec != 100000000)
{
printf ("\
!!! second timer_gettime timer_none returned it_interval %ld.%09ld\n",
(long) it.it_interval.tv_sec, it.it_interval.tv_nsec);
/* FIXME: For now disabled.
result = 1; */
}
if (timer_delete (timer_none) != 0)
{
printf ("*** timer_delete for timer_none failed: %m\n");
result = 1;
}
if (timer_delete (timer_sig1) != 0)
{
printf ("*** timer_delete for timer_sig1 failed: %m\n");
result = 1;
}
if (timer_delete (timer_sig2) != 0)
{
printf ("*** timer_delete for timer_sig2 failed: %m\n");
result = 1;
}
if (timer_delete (timer_thr1) != 0)
{
printf ("*** timer_delete for timer_thr1 failed: %m\n");
result = 1;
}
if (timer_delete (timer_thr2) != 0)
{
printf ("*** timer_delete for timer_thr2 failed: %m\n");
result = 1;
}
return result;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment