Resolved some TODOs in testing_darwinunix.c, including writing a more elaborate implementation of testingSleep().
This commit is contained in:
parent
7d29c4346d
commit
796a9cf010
|
@ -8,6 +8,7 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
#include "testing.h"
|
#include "testing.h"
|
||||||
#include "testingpriv.h"
|
#include "testingpriv.h"
|
||||||
|
|
||||||
|
@ -60,12 +61,54 @@ out:
|
||||||
|
|
||||||
void testingSleep(int64_t nsec)
|
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_sec = nsec / testingNsecPerSec;
|
||||||
duration.tv_nsec = 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 {
|
struct testingThread {
|
||||||
|
@ -85,21 +128,25 @@ static void *threadThreadProc(void *data)
|
||||||
testingThread *testingNewThread(void (*f)(void *data), void *data)
|
testingThread *testingNewThread(void (*f)(void *data), void *data)
|
||||||
{
|
{
|
||||||
testingThread *t;
|
testingThread *t;
|
||||||
|
int err;
|
||||||
|
|
||||||
t = testingprivNew(testingThread);
|
t = testingprivNew(testingThread);
|
||||||
t->f = f;
|
t->f = f;
|
||||||
t->data = data;
|
t->data = data;
|
||||||
|
|
||||||
// TODO check error
|
err = pthread_create(&(t->thread), NULL, threadThreadProc, t);
|
||||||
pthread_create(&(t->thread), NULL, threadThreadProc, t);
|
if (err != 0)
|
||||||
|
testingprivInternalError("error creating thread: %s (%d)", strerror(err), err);
|
||||||
return t;
|
return t;
|
||||||
}
|
}
|
||||||
|
|
||||||
void testingThreadWaitAndFree(testingThread *t)
|
void testingThreadWaitAndFree(testingThread *t)
|
||||||
{
|
{
|
||||||
// TODO check errors
|
int err;
|
||||||
pthread_join(t->thread, NULL);
|
|
||||||
// TODO end check errors
|
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?
|
// TODO do we need to free t->thread somehow?
|
||||||
testingprivFree(t);
|
testingprivFree(t);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue