/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifdef WIN32 #include "winport.h" #include #include /* for int64_t */ #include /* must always be included before ws2tcpip.h */ #include /* for SOCKET */ int pthread_mutex_lock(pthread_mutex_t* _mutex ){ int rc = WaitForSingleObject( *_mutex, // handle to mutex INFINITE); // no time-out interval return ((rc == WAIT_OBJECT_0) ? 0: rc); } int pthread_mutex_unlock( pthread_mutex_t* _mutex ){ int rc = ReleaseMutex(*_mutex); return ((rc != 0)? 0: GetLastError()); } int pthread_mutex_init(pthread_mutex_t* _mutex, void* ignoredAttr){ //use CreateMutex as we are using the HANDLES in pthread_cond *_mutex = CreateMutex( NULL, // default security attributes FALSE, // initially not owned NULL); // unnamed mutex return ((*_mutex == NULL) ? GetLastError() : 0); } int pthread_mutex_destroy(pthread_mutex_t* _mutex) { int rc = CloseHandle(*_mutex); return ((rc != 0)? 0: GetLastError()); } int pthread_create(pthread_t *thread, const pthread_attr_t *attr, unsigned (__stdcall* start_routine)(void* a), void *arg) { int _intThreadId; (*thread).thread_handle = (HANDLE)_beginthreadex( NULL, 0, start_routine , arg, 0, (unsigned int*)&_intThreadId ); (*thread).thread_id = _intThreadId; return (((*thread).thread_handle == 0 ) ? errno : 0 ); } int pthread_equal(pthread_t t1, pthread_t t2){ //Is there a better way to do this? GetThreadId(handle) is only supported Windows 2003 n above. return ((t1.thread_id == t2.thread_id) ? 1:0); } pthread_t pthread_self(){ pthread_t thread_self; thread_self.thread_handle = GetCurrentThread(); thread_self.thread_id = GetCurrentThreadId(); return thread_self; } int pthread_join(pthread_t _thread, void** ignore) { int rc = WaitForSingleObject( _thread.thread_handle, INFINITE ); return ((rc == WAIT_OBJECT_0) ? 0: rc); } int pthread_detach(pthread_t _thread) { int rc = CloseHandle(_thread.thread_handle) ; return (rc != 0) ? 0: GetLastError(); } void pthread_mutexattr_init(pthread_mutexattr_t* ignore){} void pthread_mutexattr_settype(pthread_mutexattr_t* ingore_attr, int ignore){} void pthread_mutexattr_destroy(pthread_mutexattr_t* ignore_attr){} int pthread_cond_init (pthread_cond_t *cv, const pthread_condattr_t * ignore) { cv->waiters_count_ = 0; cv->was_broadcast_ = 0; cv->sema_ = CreateSemaphore (NULL, // no security 0, // initially 0 0x7fffffff, // max count NULL); // unnamed if (cv->sema_ == NULL ) return GetLastError(); InitializeCriticalSection (&cv->waiters_count_lock_); cv->waiters_done_ = CreateEvent (NULL, // no security FALSE, // auto-reset FALSE, // non-signaled initially NULL); // unnamed return (cv->waiters_done_ == NULL) ? GetLastError() : 0; } int pthread_cond_destroy(pthread_cond_t *cond) { CloseHandle( cond->sema_); DeleteCriticalSection(&cond->waiters_count_lock_); return (CloseHandle( cond->waiters_done_ ) == 0)? GetLastError(): 0 ; } int pthread_cond_signal (pthread_cond_t *cv) { int have_waiters; EnterCriticalSection (& (cv->waiters_count_lock_)); have_waiters = cv->waiters_count_ > 0; LeaveCriticalSection (&cv->waiters_count_lock_); // If there aren't any waiters, then this is a no-op. if (have_waiters){ return (ReleaseSemaphore (cv->sema_, 1, 0) == 0 ) ? GetLastError() : 0 ; }else return 0; } int pthread_cond_broadcast (pthread_cond_t *cv) { // This is needed to ensure that and are // consistent relative to each other. int have_waiters = 0; EnterCriticalSection (&cv->waiters_count_lock_); if (cv->waiters_count_ > 0) { // We are broadcasting, even if there is just one waiter... // Record that we are broadcasting, which helps optimize // for the non-broadcast case. cv->was_broadcast_ = 1; have_waiters = 1; } if (have_waiters) { // Wake up all the waiters atomically. ReleaseSemaphore (cv->sema_, cv->waiters_count_, 0); LeaveCriticalSection (&cv->waiters_count_lock_); // Wait for all the awakened threads to acquire the counting // semaphore. WaitForSingleObject (cv->waiters_done_, INFINITE); // This assignment is okay, even without the held // because no other waiter threads can wake up to access it. cv->was_broadcast_ = 0; } else LeaveCriticalSection (&cv->waiters_count_lock_); } int pthread_cond_wait (pthread_cond_t *cv, pthread_mutex_t *external_mutex) { int last_waiter; // Avoid race conditions. EnterCriticalSection (&cv->waiters_count_lock_); cv->waiters_count_++; LeaveCriticalSection (&cv->waiters_count_lock_); // This call atomically releases the mutex and waits on the // semaphore until or // are called by another thread. SignalObjectAndWait (*external_mutex, cv->sema_, INFINITE, FALSE); // Reacquire lock to avoid race conditions. EnterCriticalSection (&cv->waiters_count_lock_); // We're no longer waiting... cv->waiters_count_--; // Check to see if we're the last waiter after . last_waiter = cv->was_broadcast_ && cv->waiters_count_ == 0; LeaveCriticalSection (&cv->waiters_count_lock_); // If we're the last waiter thread during this particular broadcast // then let all the other threads proceed. if (last_waiter) // This call atomically signals the event and waits until // it can acquire the . This is required to ensure fairness. SignalObjectAndWait (cv->waiters_done_, *external_mutex, INFINITE, FALSE); else // Always regain the external mutex since that's the guarantee we // give to our callers. WaitForSingleObject (*external_mutex, INFINITE); } int pthread_key_create(pthread_key_t *key, void (*destructor)(void *) ) { int result = 0; pthread_key_t* newkey; if ((newkey = (pthread_key_t*) calloc (1, sizeof (pthread_key_t))) == NULL) { result = ENOMEM; } else if ((newkey->key = TlsAlloc ()) == TLS_OUT_OF_INDEXES) { result = EAGAIN; free (newkey); newkey = NULL; } else if (destructor != NULL) { //--we have to store the function pointer for destructor, so that we can call it //--to free up the user allocated storage-- newkey->destructor = destructor; } key = newkey; return (result); } int pthread_key_delete(pthread_key_t key) { int rc = 0; LPVOID lpvData = TlsGetValue(key.key); rc = TlsFree (key.key); rc = (rc != 0 ) ? 0 : GetLastError(); if (key.destructor != NULL && lpvData != 0){ key.destructor(lpvData); //we take control of calling destructor, instead of calling it on thread exit. } free (&key); return (rc); } void *pthread_getspecific(pthread_key_t key) { LPVOID lpvData = TlsGetValue(key.key); if ((lpvData == 0) && (GetLastError() != ERROR_SUCCESS)) return NULL; else return lpvData; } int pthread_setspecific(pthread_key_t key, const void *value) { int rc = TlsSetValue (key.key, value); return ((rc != 0 ) ? 0 : GetLastError()); } int gettimeofday(struct timeval *tp, void *tzp) { int64_t now = 0; if (tzp != 0) { errno = EINVAL; return -1; } GetSystemTimeAsFileTime( (LPFILETIME)&now ); tp->tv_sec = (long)(now / 10000000 - 11644473600LL); tp->tv_usec = (now / 10) % 1000000; return 0; } int close(SOCKET fd) { return closesocket(fd); } int Win32WSAStartup() { WORD wVersionRq; WSADATA wsaData; int err; wVersionRq = MAKEWORD(2,0); err = WSAStartup(wVersionRq, &wsaData); if (err != 0) return 1; // confirm the version information if ((LOBYTE(wsaData.wVersion) != 2) || (HIBYTE(wsaData.wVersion) != 0)) { Win32WSACleanup(); return 1; } return 0; } void Win32WSACleanup() { WSACleanup(); } double drand48(void) { return (double)(rand()) / RAND_MAX; } #endif //WIN32