Resolved some TODOs in testing_darwinunix.c, including writing a more elaborate implementation of testingSleep().

This commit is contained in:
Pietro Gagliardi 2019-04-30 21:00:52 -04:00
parent 7d29c4346d
commit 796a9cf010
1 changed files with 55 additions and 8 deletions

View File

@ -8,6 +8,7 @@
#include <time.h>
#include <sys/time.h>
#include <pthread.h>
#include <unistd.h>
#include "testing.h"
#include "testingpriv.h"
@ -60,12 +61,54 @@ out:
void testingSleep(int64_t nsec)
{
struct timespec duration;
struct timespec duration, remaining;
void (*prevsig)(int);
sigset_t set, prevSet;
struct itimerval setiDuration, prevSetiDuration;
unsigned sec;
// TODO check errors, possibly falling back to usleep, setitimer/pause, or even sleep
duration.tv_sec = nsec / testingNsecPerSec;
duration.tv_nsec = nsec % testingNsecPerSec;
nanosleep(&duration, NULL);
for (;;) {
errno = 0;
if (nanosleep(&duration, &remaining) == 0)
return;
if (errno != EINTR)
break;
duration = remaining;
}
// if we got here, nanosleep() failed outright
if (sigemptyset(&set) != 0)
goto fallback;
if (sigaddset(&set, SIGABRT) != 0)
goto fallback;
if (pthread_sigmask(SIG_BLOCK, &set, &prevSet) != 0)
goto fallback;
prevsig = signal(SIGALRM, SIG_IGN);
setiDuration.it_interval.tv_sec = 0;
setiDuration.it_interval.tv_usec = 0;
// keep using duration for this in case nanosleep() was interrupted before it failed
setiDuration.it_value.tv_sec = duration.tv_sec;
setiDuration.it_value.tv_usec = duration.tv_nsec / testingNsecPerUsec;
if (setitimer(ITIMER_REAL, &setiDuration, &prevSetiDuration) != 0) {
pthread_sigmask(SIG_SETMASK, &prevSet, NULL);
signal(SIGALRM, prevsig);
goto fallback;
}
// TODO can this return an errno other than EINTR?
sigsuspend(&prevSet);
setitimer(ITIMER_REAL, &prevSetiDuration, NULL);
signal(SIGALRM, prevsig);
return;
fallback:
// hopefully we never reach this point, because it has the least granularity of all, but there are no errors, so...
sec = duration.tv_sec;
if (duration.tv_nsec > 0)
sec++;
while (sec > 0)
sec = sleep(sec);
}
struct testingThread {
@ -85,21 +128,25 @@ static void *threadThreadProc(void *data)
testingThread *testingNewThread(void (*f)(void *data), void *data)
{
testingThread *t;
int err;
t = testingprivNew(testingThread);
t->f = f;
t->data = data;
// TODO check error
pthread_create(&(t->thread), NULL, threadThreadProc, t);
err = pthread_create(&(t->thread), NULL, threadThreadProc, t);
if (err != 0)
testingprivInternalError("error creating thread: %s (%d)", strerror(err), err);
return t;
}
void testingThreadWaitAndFree(testingThread *t)
{
// TODO check errors
pthread_join(t->thread, NULL);
// TODO end check errors
int err;
err = pthread_join(t->thread, NULL);
if (err != 0)
testingprivInternalError("error waiting for thread to finish: %s (%d)", strerror(err), err);
// TODO do we need to free t->thread somehow?
testingprivFree(t);
}