1// TEST_CONFIG
2
3#include "test.h"
4
5#include <Foundation/NSObject.h>
6#include <mach/mach.h>
7#include <pthread.h>
8#include <sys/time.h>
9#include <objc/runtime.h>
10#include <objc/objc-sync.h>
11
12// Basic @synchronized tests.
13
14
15#define WAIT_SEC 3
16
17static id obj;
18static semaphore_t go;
19static semaphore_t stop;
20
21void *thread(void *arg __unused)
22{
23    int err;
24
25    objc_registerThreadWithCollector();
26
27    // non-blocking sync_enter
28    err = objc_sync_enter(obj);
29    testassert(err == OBJC_SYNC_SUCCESS);
30
31    semaphore_signal(go);
32    // main thread: sync_exit of object locked on some other thread
33    semaphore_wait(stop);
34    
35    err = objc_sync_exit(obj);
36    testassert(err == OBJC_SYNC_SUCCESS);
37    err = objc_sync_enter(obj);
38    testassert(err == OBJC_SYNC_SUCCESS);
39
40    semaphore_signal(go);
41    // main thread: blocking sync_enter 
42    testassert(WAIT_SEC/3*3 == WAIT_SEC);
43    sleep(WAIT_SEC/3);
44    // recursive enter while someone waits
45    err = objc_sync_enter(obj);
46    testassert(err == OBJC_SYNC_SUCCESS);
47    sleep(WAIT_SEC/3);
48    // recursive exit while someone waits
49    err = objc_sync_exit(obj);
50    testassert(err == OBJC_SYNC_SUCCESS);
51    sleep(WAIT_SEC/3);
52    // sync_exit while someone waits
53    err = objc_sync_exit(obj);
54    testassert(err == OBJC_SYNC_SUCCESS);
55    
56    return NULL;
57}
58
59int main()
60{
61    pthread_t th;
62    int err;
63    struct timeval start, end;
64
65    obj = [[NSObject alloc] init];
66
67    // sync_exit of never-locked object
68    err = objc_sync_exit(obj);
69    testassert(err == OBJC_SYNC_NOT_OWNING_THREAD_ERROR);
70
71    semaphore_create(mach_task_self(), &go, 0, 0);
72    semaphore_create(mach_task_self(), &stop, 0, 0);
73    pthread_create(&th, NULL, &thread, NULL);
74    semaphore_wait(go);
75
76    // sync_exit of object locked on some other thread
77    err = objc_sync_exit(obj);
78    testassert(err == OBJC_SYNC_NOT_OWNING_THREAD_ERROR);
79
80    semaphore_signal(stop);
81    semaphore_wait(go);
82
83    // blocking sync_enter
84    gettimeofday(&start, NULL);
85    err = objc_sync_enter(obj);
86    gettimeofday(&end, NULL);
87    testassert(err == OBJC_SYNC_SUCCESS);
88    // should have waited more than WAIT_SEC but less than WAIT_SEC+1
89    // fixme hack: sleep(1) is ending 500 usec too early on x86_64 buildbot
90    // (rdar://6456975)
91    testassert(end.tv_sec*1000000LL+end.tv_usec >= 
92               start.tv_sec*1000000LL+start.tv_usec + WAIT_SEC*1000000LL
93               - 3*500 /*hack*/);
94    testassert(end.tv_sec*1000000LL+end.tv_usec < 
95               start.tv_sec*1000000LL+start.tv_usec + (1+WAIT_SEC)*1000000LL);
96
97    err = objc_sync_exit(obj);
98    testassert(err == OBJC_SYNC_SUCCESS);
99
100    err = objc_sync_exit(obj);
101    testassert(err == OBJC_SYNC_NOT_OWNING_THREAD_ERROR);
102
103    succeed(__FILE__);
104}
105