[libdispatch-changes] [192] trunk/src

source_changes at macosforge.org source_changes at macosforge.org
Sun Oct 24 01:25:55 PDT 2010


Revision: 192
          http://trac.macosforge.org/projects/libdispatch/changeset/192
Author:   kvv at apple.com
Date:     2010-10-24 01:25:52 -0700 (Sun, 24 Oct 2010)
Log Message:
-----------
Support for time and semaphores on Win32.

Modified Paths:
--------------
    trunk/src/internal.h
    trunk/src/queue.c
    trunk/src/semaphore.c
    trunk/src/semaphore_internal.h
    trunk/src/shims/time.c
    trunk/src/shims/time.h
    trunk/src/time.c

Modified: trunk/src/internal.h
===================================================================
--- trunk/src/internal.h	2010-10-24 07:29:08 UTC (rev 191)
+++ trunk/src/internal.h	2010-10-24 08:25:52 UTC (rev 192)
@@ -29,6 +29,37 @@
 
 #include "config/config.h"
 
+#ifdef __APPLE__
+#include <TargetConditionals.h>
+#endif
+
+#if TARGET_OS_WIN32
+// Include Win32 headers early in order to minimize the
+// likelihood of name pollution from dispatch headers.
+
+#ifndef WINVER
+#define WINVER 0x502
+#endif
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x502
+#endif
+
+#ifndef _MSC_VER
+#define _MSC_VER 1400
+#pragma warning(disable:4159)
+#endif
+
+#define WIN32_LEAN_AND_MEAN 1
+#define _CRT_SECURE_NO_DEPRECATE 1
+#define _CRT_SECURE_NO_WARNINGS 1
+
+#define BOOL WINBOOL
+#include <Windows.h>
+#undef BOOL
+
+#endif /* TARGET_OS_WIN32 */
+
 #define __DISPATCH_BUILDING_DISPATCH__
 #define __DISPATCH_INDIRECT__
 
@@ -96,6 +127,9 @@
 #include <netinet/in.h>
 
 #ifdef __BLOCKS__
+#if TARGET_OS_WIN32
+#define BLOCK_EXPORT extern "C" __declspec(dllexport)
+#endif /* TARGET_OS_WIN32 */
 #include <Block_private.h>
 #include <Block.h>
 #endif /* __BLOCKS__ */

Modified: trunk/src/queue.c
===================================================================
--- trunk/src/queue.c	2010-10-24 07:29:08 UTC (rev 191)
+++ trunk/src/queue.c	2010-10-24 08:25:52 UTC (rev 192)
@@ -1200,6 +1200,10 @@
 			ret = sem_init(&_dispatch_thread_mediator[i].dsema_sem, 0, 0);
 			(void)dispatch_assume_zero(ret);
 #endif
+#if USE_WIN32_SEM
+			_dispatch_thread_mediator[i].dsema_handle = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
+			dispatch_assume(_dispatch_thread_mediator[i].dsema_handle);
+#endif
 #if HAVE_PTHREAD_WORKQUEUES
 		} else {
 			dispatch_assume(_dispatch_root_queue_contexts[i].dgq_kworkqueue);

Modified: trunk/src/semaphore.c
===================================================================
--- trunk/src/semaphore.c	2010-10-24 07:29:08 UTC (rev 191)
+++ trunk/src/semaphore.c	2010-10-24 08:25:52 UTC (rev 192)
@@ -56,7 +56,7 @@
 {
 	dispatch_semaphore_t dsema;
 	
-	dsema = fastpath(_dispatch_thread_getspecific(dispatch_sema4_key));
+	dsema = (dispatch_semaphore_t)fastpath(_dispatch_thread_getspecific(dispatch_sema4_key));
 	if (!dsema) {
 		while (!(dsema = dispatch_semaphore_create(0))) {
 			sleep(1);
@@ -69,7 +69,7 @@
 void
 _dispatch_put_thread_semaphore(dispatch_semaphore_t dsema)
 {
-	dispatch_semaphore_t old_sema = _dispatch_thread_getspecific(dispatch_sema4_key);
+	dispatch_semaphore_t old_sema = (dispatch_semaphore_t)_dispatch_thread_getspecific(dispatch_sema4_key);
 	_dispatch_thread_setspecific(dispatch_sema4_key, dsema);
 	if (old_sema) {
 		dispatch_release(old_sema);
@@ -97,11 +97,11 @@
 		return NULL;
 	}
 	
-	dsema = calloc(1, sizeof(struct dispatch_semaphore_s));
+	dsema = (dispatch_semaphore_t)calloc(1, sizeof(struct dispatch_semaphore_s));
 	
 	if (fastpath(dsema)) {
 		dsema->do_vtable = &_dispatch_semaphore_vtable;
-		dsema->do_next = DISPATCH_OBJECT_LISTLESS;
+		dsema->do_next = (dispatch_semaphore_t)DISPATCH_OBJECT_LISTLESS;
 		dsema->do_ref_cnt = 1;
 		dsema->do_xref_cnt = 1;
 		dsema->do_targetq = dispatch_get_global_queue(0, 0);
@@ -148,6 +148,28 @@
 }
 #endif
 
+#if USE_WIN32_SEM
+static void
+_dispatch_semaphore_create_handle(HANDLE *s4)
+{
+	HANDLE tmp;
+
+	if (*s4) {
+		return;
+	}
+
+	// lazily allocate the semaphore port
+
+	while (dispatch_assume(tmp = CreateSemaphore(NULL, 0, LONG_MAX, NULL)) == NULL) {
+		sleep(1);
+	}
+
+	if (!dispatch_atomic_cmpxchg(s4, 0, tmp)) {
+		CloseHandle(tmp);
+	}
+}
+#endif /* USE_WIN32_SEM */
+
 DISPATCH_NOINLINE
 static long
 _dispatch_semaphore_wait_slow(dispatch_semaphore_t dsema, dispatch_time_t timeout)
@@ -155,10 +177,11 @@
 #if USE_MACH_SEM
 	mach_timespec_t _timeout;
 	kern_return_t kr;
-	uint64_t nsec;
 #endif
 #if USE_POSIX_SEM
 	struct timespec _timeout;
+#endif
+#if USE_POSIX_SEM || USE_WIN32_SEM
 	int ret;
 #endif
 	long orig;
@@ -176,6 +199,9 @@
 #if USE_MACH_SEM
 	_dispatch_semaphore_create_port(&dsema->dsema_port);
 #endif
+#if USE_WIN32_SEM
+	_dispatch_semaphore_create_handle(&dsema->dsema_handle);
+#endif
 
 	// From xnu/osfmk/kern/sync_sema.c:
 	// wait_semaphore->count = -1;  /* we don't keep an actual count */
@@ -189,6 +215,7 @@
 	default:
 #if USE_MACH_SEM
 		do {
+			uint64_t nsec;
 			// timeout() already calculates relative time left
 			nsec = _dispatch_timeout(timeout);
 			_timeout.tv_sec = (typeof(_timeout.tv_sec))(nsec / NSEC_PER_SEC);
@@ -213,6 +240,18 @@
 			break;
 		}
 #endif
+#if USE_WIN32_SEM
+		do {
+			uint64_t nsec;
+			DWORD msec;
+			nsec = _dispatch_timeout(timeout);
+			msec = (DWORD)(nsec / (uint64_t)1000000);
+			ret = WaitForSingleObject(dsema->dsema_handle, msec);
+		} while (ret != WAIT_OBJECT_0 && ret != WAIT_TIMEOUT);
+		if (ret != WAIT_TIMEOUT) {
+			break;
+		}
+#endif /* USE_WIN32_SEM */
 		// Fall through and try to undo what the fast path did to dsema->dsema_value
 	case DISPATCH_TIME_NOW:
 		while ((orig = dsema->dsema_value) < 0) {
@@ -220,7 +259,7 @@
 #if USE_MACH_SEM
 				return KERN_OPERATION_TIMED_OUT;
 #endif
-#if USE_POSIX_SEM
+#if USE_POSIX_SEM || USE_WIN32_SEM
 				errno = ETIMEDOUT;
 				return -1;
 #endif
@@ -241,6 +280,11 @@
 		} while (ret != 0);
 		DISPATCH_SEMAPHORE_VERIFY_RET(ret);
 #endif
+#if USE_WIN32_SEM
+		do {
+			ret = WaitForSingleObject(dsema->dsema_handle, INFINITE);
+		} while (ret != WAIT_OBJECT_0);
+#endif
 		break;
 	}
 
@@ -311,7 +355,7 @@
 static long
 _dispatch_semaphore_signal_slow(dispatch_semaphore_t dsema)
 {
-#if USE_POSIX_SEM
+#if USE_POSIX_SEM || USE_WIN32_SEM
 	int ret;
 #endif
 #if USE_MACH_SEM
@@ -319,6 +363,9 @@
 	
 	_dispatch_semaphore_create_port(&dsema->dsema_port);
 #endif
+#if USE_WIN32_SEM
+	_dispatch_semaphore_create_handle(&dsema->dsema_handle);
+#endif
 
 	// Before dsema_sent_ksignals is incremented we can rely on the reference
 	// held by the waiter. However, once this value is incremented the waiter
@@ -337,6 +384,10 @@
 	ret = sem_post(&dsema->dsema_sem);
 	DISPATCH_SEMAPHORE_VERIFY_RET(ret);
 #endif
+#if USE_WIN32_SEM
+	// Signal the semaphore.
+	ret = ReleaseSemaphore(dsema->dsema_handle, 1, NULL);
+#endif
 
 	_dispatch_release(dsema);
 	
@@ -391,13 +442,14 @@
 long
 _dispatch_group_wake(dispatch_semaphore_t dsema)
 {
-	struct dispatch_sema_notify_s *tmp, *head = dispatch_atomic_xchg(&dsema->dsema_notify_head, NULL);
-	long rval = dispatch_atomic_xchg(&dsema->dsema_group_waiters, 0);
-	bool do_rel = head;
+	struct dispatch_sema_notify_s *tmp;
+	struct dispatch_sema_notify_s *head = (struct dispatch_sema_notify_s *)dispatch_atomic_xchg(&dsema->dsema_notify_head, NULL);
+	long rval = (long)dispatch_atomic_xchg(&dsema->dsema_group_waiters, 0);
+	bool do_rel = (head != NULL);
 #if USE_MACH_SEM
 	long kr;
 #endif
-#if USE_POSIX_SEM
+#if USE_POSIX_SEM || USE_WIN32_SEM
 	int ret;
 #endif
 
@@ -417,6 +469,11 @@
 			DISPATCH_SEMAPHORE_VERIFY_RET(ret);
 		} while (--rval);
 #endif
+#if USE_WIN32_SEM
+		// Signal the semaphore.
+		ret = ReleaseSemaphore(dsema->dsema_waiter_handle, 1, NULL);
+		dispatch_assume(ret);
+#endif
 	}
 	while (head) {
 		dispatch_async_f(head->dsn_queue, head->dsn_ctxt, head->dsn_func);
@@ -440,10 +497,11 @@
 #if USE_MACH_SEM
 	mach_timespec_t _timeout;
 	kern_return_t kr;
-	uint64_t nsec;
 #endif
 #if USE_POSIX_SEM
 	struct timespec _timeout;
+#endif
+#if USE_POSIX_SEM || USE_WIN32_SEM
 	int ret;
 #endif
 	long orig;
@@ -456,7 +514,7 @@
 	// Mach semaphores appear to sometimes spuriously wake up.  Therefore,
 	// we keep a parallel count of the number of times a Mach semaphore is
 	// signaled (6880961).
-	dispatch_atomic_inc(&dsema->dsema_group_waiters);
+	(void)dispatch_atomic_inc(&dsema->dsema_group_waiters);
 	// check the values again in case we need to wake any threads
 	if (dsema->dsema_value == dsema->dsema_orig) {
 		return _dispatch_group_wake(dsema);
@@ -478,6 +536,7 @@
 	default:
 #if USE_MACH_SEM
 		do {
+			uint64_t nsec;
 			nsec = _dispatch_timeout(timeout);
 			_timeout.tv_sec = (typeof(_timeout.tv_sec))(nsec / NSEC_PER_SEC);
 			_timeout.tv_nsec = (typeof(_timeout.tv_nsec))(nsec % NSEC_PER_SEC);
@@ -500,6 +559,18 @@
 			break;
 		}
 #endif
+#if USE_WIN32_SEM
+		do {
+			uint64_t nsec;
+			DWORD msec;
+			nsec = _dispatch_timeout(timeout);
+			msec = (DWORD)(nsec / (uint64_t)1000000);
+			ret = WaitForSingleObject(dsema->dsema_waiter_handle, msec);
+		} while (ret != WAIT_OBJECT_0 && ret != WAIT_TIMEOUT);
+		if (ret == WAIT_TIMEOUT) {
+			break;
+		}
+#endif /* USE_WIN32_SEM */
 		// Fall through and try to undo the earlier change to dsema->dsema_group_waiters
 	case DISPATCH_TIME_NOW:
 		while ((orig = dsema->dsema_group_waiters)) {
@@ -507,7 +578,7 @@
 #if USE_MACH_SEM
 				return KERN_OPERATION_TIMED_OUT;
 #endif
-#if USE_POSIX_SEM
+#if USE_POSIX_SEM || USE_WIN32_SEM
 				errno = ETIMEDOUT;
 				return -1;
 #endif
@@ -528,6 +599,12 @@
 		} while (ret == -1 && errno == EINTR);
 		DISPATCH_SEMAPHORE_VERIFY_RET(ret);
 #endif
+#if USE_WIN32_SEM
+		do {
+			ret = WaitForSingleObject(dsema->dsema_waiter_handle, INFINITE);
+		} while (ret != WAIT_OBJECT_0);
+#endif
+
 		break;
 	}
 
@@ -546,7 +623,7 @@
 #if USE_MACH_SEM
 		return KERN_OPERATION_TIMED_OUT;
 #endif
-#if USE_POSIX_SEM
+#if USE_POSIX_SEM || USE_WIN32_SEM
 		errno = ETIMEDOUT;
 		return (-1);
 #endif
@@ -569,7 +646,7 @@
 	struct dispatch_sema_notify_s *dsn, *prev;
 
 	// FIXME -- this should be updated to use the continuation cache
-	while (!(dsn = malloc(sizeof(*dsn)))) {
+	while (!(dsn = (struct dispatch_sema_notify_s *)malloc(sizeof(*dsn)))) {
 		sleep(1);
 	}
 
@@ -579,7 +656,7 @@
 	dsn->dsn_func = func;
 	_dispatch_retain(dq);
 
-	prev = dispatch_atomic_xchg(&dsema->dsema_notify_tail, dsn);
+	prev = (struct dispatch_sema_notify_s *)dispatch_atomic_xchg(&dsema->dsema_notify_tail, dsn);
 	if (fastpath(prev)) {
 		prev->dsn_next = dsn;
 	} else {
@@ -619,7 +696,15 @@
 	ret = sem_destroy(&dsema->dsema_sem);
 	DISPATCH_SEMAPHORE_VERIFY_RET(ret);
 #endif
-	
+#if USE_WIN32_SEM
+	if (dsema->dsema_handle) {
+		CloseHandle(dsema->dsema_handle);
+	}
+	if (dsema->dsema_waiter_handle) {
+		CloseHandle(dsema->dsema_waiter_handle);
+	}
+#endif
+
 	_dispatch_dispose(dsema);
 }
 
@@ -655,7 +740,10 @@
 	_dispatch_retain(dg);
 	dispatch_group_enter(dg);
 
-	dc = _dispatch_continuation_alloc_cacheonly() ?: _dispatch_continuation_alloc_from_heap();
+	dc = _dispatch_continuation_alloc_cacheonly();
+	if (dc == NULL) {
+		dc = _dispatch_continuation_alloc_from_heap();
+	}
 
 	dc->do_vtable = (void *)(DISPATCH_OBJ_ASYNC_BIT|DISPATCH_OBJ_GROUP_BIT);
 	dc->dc_func = func;

Modified: trunk/src/semaphore_internal.h
===================================================================
--- trunk/src/semaphore_internal.h	2010-10-24 07:29:08 UTC (rev 191)
+++ trunk/src/semaphore_internal.h	2010-10-24 08:25:52 UTC (rev 192)
@@ -39,13 +39,16 @@
 	long dsema_value;
 	long dsema_orig;
 	size_t dsema_sent_ksignals;
-#if USE_MACH_SEM && USE_POSIX_SEM
+#if (USE_MACH_SEM + USE_POSIX_SEM + USE_WIN32_SEM) > 1
 #error "Too many supported semaphore types"
 #elif USE_MACH_SEM
 	semaphore_t dsema_port;
 	semaphore_t dsema_waiter_port;
 #elif USE_POSIX_SEM
 	sem_t dsema_sem;
+#elif USE_WIN32_SEM
+	HANDLE dsema_handle;
+	HANDLE dsema_waiter_handle;
 #else
 #error "No supported semaphore type"
 #endif

Modified: trunk/src/shims/time.c
===================================================================
--- trunk/src/shims/time.c	2010-10-24 07:29:08 UTC (rev 191)
+++ trunk/src/shims/time.c	2010-10-24 08:25:52 UTC (rev 192)
@@ -20,17 +20,23 @@
 
 #include "internal.h"
 
-// for architectures that don't always return mach_absolute_time() in nanoseconds
-#if !(defined(__i386__) || defined(__x86_64__) || !defined(HAVE_MACH_ABSOLUTE_TIME))
+#if !(defined(__i386__) || defined(__x86_64__)) || !HAVE_MACH_ABSOLUTE_TIME
 _dispatch_host_time_data_s _dispatch_host_time_data;
 
 void
 _dispatch_get_host_time_init(void *context __attribute__((unused)))
 {
+#if HAVE_MACH_ABSOLUTE_TIME
 	mach_timebase_info_data_t tbi;
 	(void)dispatch_assume_zero(mach_timebase_info(&tbi));
 	_dispatch_host_time_data.frac = tbi.numer;
 	_dispatch_host_time_data.frac /= tbi.denom;
 	_dispatch_host_time_data.ratio_1_to_1 = (tbi.numer == tbi.denom);
+#elif TARGET_OS_WIN32
+	LARGE_INTEGER freq;
+	dispatch_assume(QueryPerformanceFrequency(&freq));
+	_dispatch_host_time_data.frac = (long double)NSEC_PER_SEC / (long double)freq.QuadPart;
+	_dispatch_host_time_data.ratio_1_to_1 = (freq.QuadPart == 1);
+#endif /* TARGET_OS_WIN32 */
 }
 #endif

Modified: trunk/src/shims/time.h
===================================================================
--- trunk/src/shims/time.h	2010-10-24 07:29:08 UTC (rev 191)
+++ trunk/src/shims/time.h	2010-10-24 08:25:52 UTC (rev 192)
@@ -31,8 +31,19 @@
 #error "Please #include <dispatch/dispatch.h> instead of this file directly."
 #endif
 
-#if defined(__i386__) || defined(__x86_64__) || !defined(HAVE_MACH_ABSOLUTE_TIME)
-// these architectures always return mach_absolute_time() in nanoseconds
+uint64_t _dispatch_get_nanoseconds(void);
+
+#if TARGET_OS_WIN32
+static inline unsigned int
+sleep(unsigned int seconds)
+{
+	Sleep(seconds * 1000); // milliseconds
+	return 0;
+}
+#endif
+
+#if (defined(__i386__) || defined(__x86_64__)) && HAVE_MACH_ABSOLUTE_TIME
+// x86 currently implements mach time in nanoseconds; this is NOT likely to change
 #define _dispatch_time_mach2nano(x) (x)
 #define _dispatch_time_nano2mach(x) (x)
 #else
@@ -84,6 +95,12 @@
 {
 #if HAVE_MACH_ABSOLUTE_TIME
 	return mach_absolute_time();
+#elif TARGET_OS_WIN32
+	LARGE_INTEGER now;
+	if (!QueryPerformanceCounter(&now)) {
+		return 0;
+	}
+	return now.QuadPart;
 #else
 	struct timespec ts;
 	int ret;

Modified: trunk/src/time.c
===================================================================
--- trunk/src/time.c	2010-10-24 07:29:08 UTC (rev 191)
+++ trunk/src/time.c	2010-10-24 08:25:52 UTC (rev 192)
@@ -23,12 +23,22 @@
 uint64_t 
 _dispatch_get_nanoseconds(void)
 {
+#if !TARGET_OS_WIN32
 	struct timeval now;
 	int r = gettimeofday(&now, NULL);
 	dispatch_assert_zero(r);
 	dispatch_assert(sizeof(NSEC_PER_SEC) == 8);
 	dispatch_assert(sizeof(NSEC_PER_USEC) == 8);
 	return now.tv_sec * NSEC_PER_SEC + now.tv_usec * NSEC_PER_USEC;
+#else /* TARGET_OS_WIN32 */
+	// FILETIME is 100-nanosecond intervals since January 1, 1601 (UTC).
+	FILETIME ft;
+	ULARGE_INTEGER li;
+	GetSystemTimeAsFileTime(&ft);
+	li.LowPart = ft.dwLowDateTime;
+	li.HighPart = ft.dwHighDateTime;
+	return li.QuadPart * 100ull;
+#endif /* TARGET_OS_WIN32 */
 }
 
 dispatch_time_t
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/libdispatch-changes/attachments/20101024/295df262/attachment-0001.html>


More information about the libdispatch-changes mailing list