darling-objc4/test/synchronized.m
2020-06-09 21:50:17 -04:00

115 lines
2.9 KiB
Objective-C

// TEST_CONFIG
#include "test.h"
#include <Foundation/NSObject.h>
#include <mach/mach.h>
#include <pthread.h>
#include <sys/time.h>
#include <objc/runtime.h>
#include <objc/objc-sync.h>
// Basic @synchronized tests.
#define WAIT_SEC 3
static id obj;
static semaphore_t go;
static semaphore_t stop;
void *thread(void *arg __unused)
{
int err;
BOOL locked;
// non-blocking sync_enter
err = objc_sync_enter(obj);
testassert(err == OBJC_SYNC_SUCCESS);
// recursive try_sync_enter
locked = objc_sync_try_enter(obj);
testassert(locked);
err = objc_sync_exit(obj);
testassert(err == OBJC_SYNC_SUCCESS);
semaphore_signal(go);
// main thread: sync_exit of object locked on some other thread
semaphore_wait(stop);
err = objc_sync_exit(obj);
testassert(err == OBJC_SYNC_SUCCESS);
err = objc_sync_enter(obj);
testassert(err == OBJC_SYNC_SUCCESS);
semaphore_signal(go);
// main thread: blocking sync_enter
testassert(WAIT_SEC/3*3 == WAIT_SEC);
sleep(WAIT_SEC/3);
// recursive enter while someone waits
err = objc_sync_enter(obj);
testassert(err == OBJC_SYNC_SUCCESS);
sleep(WAIT_SEC/3);
// recursive exit while someone waits
err = objc_sync_exit(obj);
testassert(err == OBJC_SYNC_SUCCESS);
sleep(WAIT_SEC/3);
// sync_exit while someone waits
err = objc_sync_exit(obj);
testassert(err == OBJC_SYNC_SUCCESS);
return NULL;
}
int main()
{
pthread_t th;
int err;
struct timeval start, end;
BOOL locked;
obj = [[NSObject alloc] init];
// sync_exit of never-locked object
err = objc_sync_exit(obj);
testassert(err == OBJC_SYNC_NOT_OWNING_THREAD_ERROR);
semaphore_create(mach_task_self(), &go, 0, 0);
semaphore_create(mach_task_self(), &stop, 0, 0);
pthread_create(&th, NULL, &thread, NULL);
semaphore_wait(go);
// sync_exit of object locked on some other thread
err = objc_sync_exit(obj);
testassert(err == OBJC_SYNC_NOT_OWNING_THREAD_ERROR);
semaphore_signal(stop);
semaphore_wait(go);
// contended try_sync_enter
locked = objc_sync_try_enter(obj);
testassert(!locked);
// blocking sync_enter
gettimeofday(&start, NULL);
err = objc_sync_enter(obj);
gettimeofday(&end, NULL);
testassert(err == OBJC_SYNC_SUCCESS);
// should have waited more than WAIT_SEC but less than WAIT_SEC+1
// fixme hack: sleep(1) is ending 500 usec too early on x86_64 buildbot
// (rdar://6456975)
testassert(end.tv_sec*1000000LL+end.tv_usec >=
start.tv_sec*1000000LL+start.tv_usec + WAIT_SEC*1000000LL
- 3*500 /*hack*/);
testassert(end.tv_sec*1000000LL+end.tv_usec <
start.tv_sec*1000000LL+start.tv_usec + (1+WAIT_SEC)*1000000LL);
err = objc_sync_exit(obj);
testassert(err == OBJC_SYNC_SUCCESS);
err = objc_sync_exit(obj);
testassert(err == OBJC_SYNC_NOT_OWNING_THREAD_ERROR);
succeed(__FILE__);
}