Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Portability layer over the pthreads working with pthread or on windows
authormquinson <mquinson@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
Thu, 8 Mar 2007 16:17:40 +0000 (16:17 +0000)
committermquinson <mquinson@48e7efb5-ca39-0410-a469-dd3cf9ba447f>
Thu, 8 Mar 2007 16:17:40 +0000 (16:17 +0000)
git-svn-id: svn+ssh://scm.gforge.inria.fr/svn/simgrid/simgrid/trunk@3210 48e7efb5-ca39-0410-a469-dd3cf9ba447f

include/xbt/xbt_thread.h [new file with mode: 0644]
src/xbt/xbt_thread.c [new file with mode: 0644]

diff --git a/include/xbt/xbt_thread.h b/include/xbt/xbt_thread.h
new file mode 100644 (file)
index 0000000..ae28b51
--- /dev/null
@@ -0,0 +1,60 @@
+/* $Id$ */
+
+/* xbt/xbt_thread.h -- Thread portability layer                             */
+
+/* Copyright (c) 2007 Martin Quinson. All rights reserved.                  */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+
+#ifndef _XBT_THREAD_H
+#define _XBT_THREAD_H
+
+#include "xbt/misc.h" /* SG_BEGIN_DECL */
+#include "xbt/function_types.h"
+
+SG_BEGIN_DECL()
+
+/** @addtogroup XBT_thread
+ *  @brief Thread portability layer
+ * 
+ *  This section describes the thread portability layer. It defines types and 
+ *  functions very close to the pthread API, but it's portable to windows too.
+ * 
+ *  @{
+ */
+
+  /** \brief Thread data type (opaque structure) */
+  typedef struct xbt_thread_       *xbt_thread_t;
+
+  XBT_PUBLIC(xbt_thread_t) xbt_thread_create(pvoid_f_pvoid_t start_routine,void* param);
+  XBT_PUBLIC(void) xbt_thread_exit(int *retcode);
+  XBT_PUBLIC(xbt_thread_t) xbt_thread_self(void);
+  XBT_PUBLIC(void) xbt_thread_yield(void);
+
+
+  /** \brief Thread mutex data type (opaque structure) */
+  typedef struct xbt_mutex_ *xbt_mutex_t;
+
+  XBT_PUBLIC(xbt_mutex_t) xbt_mutex_init(void);
+  XBT_PUBLIC(void)        xbt_mutex_lock(xbt_mutex_t mutex);
+  XBT_PUBLIC(void)        xbt_mutex_unlock(xbt_mutex_t mutex);
+  XBT_PUBLIC(void)        xbt_mutex_destroy(xbt_mutex_t mutex);
+
+
+  /** \brief Thread condition data type (opaque structure) */
+  typedef struct xbt_thcond_  *xbt_thcond_t;
+
+  XBT_PUBLIC(xbt_thcond_t) xbt_thcond_init(void);
+  XBT_PUBLIC(void)         xbt_thcond_wait(xbt_thcond_t cond,
+                                          xbt_mutex_t mutex);
+  XBT_PUBLIC(void)         xbt_thcond_signal(xbt_thcond_t cond);
+  XBT_PUBLIC(void)         xbt_thcond_broadcast(xbt_thcond_t cond);
+  XBT_PUBLIC(void)         xbt_thcond_destroy(xbt_thcond_t cond);
+
+/** @} */
+
+SG_END_DECL()
+
+#endif /* _XBT_DICT_H */
diff --git a/src/xbt/xbt_thread.c b/src/xbt/xbt_thread.c
new file mode 100644 (file)
index 0000000..2ca9e91
--- /dev/null
@@ -0,0 +1,339 @@
+/* $Id$ */
+
+/* xbt_thread -- portability layer over the pthread API                     */
+
+/* Copyright 2006,2007 Malek Cherier, Martin Quinson          
+ * All right reserved.                                                      */
+
+/* This program is free software; you can redistribute it and/or modify it
+ * under the terms of the license (GNU LGPL) which comes with this package. */
+
+#include "xbt/sysdep.h"
+#include "xbt/ex.h"
+#include "portable.h"
+#include "xbt/xbt_thread.h" /* This module */
+#include "xbt_modinter.h" /* Initialization/finalization of this module */
+
+#ifdef HAVE_PTHREAD_H
+#include <pthread.h>
+
+typedef struct xbt_thread_ {
+   pthread_t t;
+} s_xbt_thread_t ;
+
+/* frees the xbt_thread_t corresponding to the current thread */
+static void xbt_thread_free_thread_data(void*d){
+   free(d);
+}
+
+pthread_key_t thread_data; /* thread-specific data containing the xbt_thread_t structure */
+void xbt_thread_mod_init(void) {
+   int errcode;
+   
+   if ((errcode=pthread_key_create(&thread_data, &xbt_thread_free_thread_data)))
+     THROW0(system_error,errcode,"pthread_key_create failed for thread_data");
+}
+void xbt_thread_mod_exit(void) {
+   int errcode;
+   
+   if ((errcode=pthread_key_delete(thread_data)))
+     THROW0(system_error,errcode,"pthread_key_delete failed for thread_data");
+}
+
+
+xbt_thread_t xbt_thread_create(pvoid_f_pvoid_t start_routine,
+                              void* param)  {
+   xbt_thread_t res = xbt_new(s_xbt_thread_t,1);
+   int errcode;
+
+   if ((errcode=pthread_setspecific(thread_data,res)))
+     THROW0(system_error,errcode,"pthread_setspecific failed for thread_data");
+      
+   if ((errcode = pthread_create(&(res->t), NULL, start_routine, param)))
+     THROW0(system_error,errcode, "pthread_create failed");
+   
+   return res;
+}                     
+void xbt_thread_exit(int *retval) {
+   pthread_exit(retval);
+}
+xbt_thread_t xbt_thread_self(void) {
+   return pthread_getspecific(thread_data);
+}
+
+#include <sched.h>
+void xbt_thread_yield(void) {
+   sched_yield();
+}
+/****** mutex related functions ******/
+typedef struct xbt_mutex_ {
+   pthread_mutex_t m;
+} s_xbt_mutex_t;
+
+xbt_mutex_t xbt_mutex_init(void) {
+   xbt_mutex_t res = xbt_new(s_xbt_mutex_t,1);
+   int errcode;
+   
+   if ((errcode = pthread_mutex_init(&(res->m),NULL)))
+     THROW0(system_error,errcode,"pthread_mutex_init() failed");
+   
+   return res;
+}
+
+void xbt_mutex_lock(xbt_mutex_t mutex) {
+   int errcode;
+   
+   if ((errcode=pthread_mutex_lock(&(mutex->m))))
+     THROW1(system_error,errcode,"pthread_mutex_lock(%p) failed",mutex);
+}
+
+void xbt_mutex_unlock(xbt_mutex_t mutex) {
+   int errcode;
+   
+   if ((errcode=pthread_mutex_unlock(&(mutex->m))))
+     THROW1(system_error,errcode,"pthread_mutex_unlock(%p) failed",mutex);
+}
+
+void xbt_mutex_destroy(xbt_mutex_t mutex) {
+   int errcode;
+   
+   if ((errcode=pthread_mutex_destroy(&(mutex->m))))
+     THROW1(system_error,errcode,"pthread_mutex_destroy(%p) failed",mutex);
+   free(mutex);
+}
+
+/***** condition related functions *****/
+typedef struct xbt_thcond_ {
+   pthread_cond_t c;
+} s_xbt_thcond_t;
+
+xbt_thcond_t xbt_thcond_init(void) {
+   xbt_thcond_t res = xbt_new(s_xbt_thcond_t,1);
+   int errcode;
+   if ((errcode=pthread_cond_init(&(res->c),NULL)))
+     THROW0(system_error,errcode,"pthread_cond_init() failed");
+
+   return res;
+}
+
+void xbt_thcond_wait(xbt_thcond_t cond, xbt_mutex_t mutex) {
+   int errcode;
+   if ((errcode=pthread_cond_wait(&(cond->c),&(mutex->m))))
+     THROW2(system_error,errcode,"pthread_cond_wait(%p,%p) failed",cond,mutex);
+}
+
+void xbt_thcond_signal(xbt_thcond_t cond) {
+   int errcode;
+   if ((errcode=pthread_cond_signal(&(cond->c))))
+     THROW1(system_error,errcode,"pthread_cond_signal(%p) failed",cond);
+}
+        
+void xbt_thcond_broadcast(xbt_thcond_t cond){
+   int errcode;
+   if ((errcode=pthread_cond_broadcast(&(cond->c))))
+     THROW1(system_error,errcode,"pthread_cond_broadcast(%p) failed",cond);
+}
+void xbt_thcond_destroy(xbt_thcond_t cond){
+   int errcode;
+   if ((errcode=pthread_cond_destroy(&(cond->c))))
+     THROW1(system_error,errcode,"pthread_cond_destroy(%p) failed",cond);
+   free(cond);
+}
+
+
+#elif defined(WIN32)
+typedef struct xbt_thread_ {
+   HANDLE handle;                  /* the win thread handle        */
+   unsigned long id;               /* the win thread id            */
+} s_xbt_thread_t ;
+
+void xbt_thread_mod_init(void) {}
+void xbt_thread_mod_exit(void) {}
+
+xbt_thread_t xbt_thread_create(pvoid_f_pvoid_t start_routine,
+                              void* param)  {
+   
+   xbt_thread_t res = xbt_new(s_xbt_thread_t,1);
+   
+   res->handle = CreateThread(NULL,NULL,start_routine,param,0,&((*thread)->id));
+       
+   if(!res->handle) {
+     xbt_free(res);
+     THROW0(system_error,errcode,"CreateThread failed");
+   }
+   
+   return res;
+}
+
+void xbt_thread_exit(int *retval) {
+   xbt_thread_t self = xbt_thread_self();
+   
+   CloseHandle(self->handle);
+   free(self);
+   
+   ExitThread(*retval);
+}
+
+xbt_thread_t xbt_thread_self(void) {
+   return GetCurrentThreadId();
+}
+
+void xbt_thread_yield(void) {
+    Sleep(0);
+}
+
+/****** mutex related functions ******/
+typedef struct xbt_mutex_ {
+   CRITICAL_SECTION lock;   
+} s_xbt_mutex_t;
+
+xbt_mutex_t xbt_mutex_init(void) {
+   xbt_mutex_t res = xbt_new(s_xbt_mutex_t,1);
+
+   /* initialize the critical section object */
+   InitializeCriticalSection(&(res->lock));
+   
+   return res;
+}
+
+void xbt_mutex_lock(xbt_mutex_t mutex) {
+
+   EnterCriticalSection(& mutex->lock);
+}
+
+void xbt_mutex_unlock(xbt_mutex_t mutex) {
+
+   LeaveCriticalSection (& mutex->lock);
+
+}
+
+void xbt_mutex_destroy(xbt_mutex_t mutex) {
+
+   DeleteCriticalSection(& mutex->lock);
+               
+   free(mutex);
+}
+
+/***** condition related functions *****/
+typedef struct xbt_thcond_ {
+   HANDLE events[MAX_EVENTS];
+   
+   unsigned int waiters_count;           /* the number of waiters                        */
+   CRITICAL_SECTION waiters_count_lock;  /* protect access to waiters_count  */
+} s_xbt_thcond_t;
+
+xbt_thcond_t xbt_thcond_init(void) {
+
+   xbt_thcond_t res = xbt_new0(s_xbt_thcond_t,1);
+       
+   memset(& res->waiters_count_lock,0,sizeof(CRITICAL_SECTION));
+       
+   /* initialize the critical section object */
+   InitializeCriticalSection(& res->waiters_count_lock);
+       
+   res->waiters_count = 0;
+       
+   /* Create an auto-reset event */
+   res->events[SIGNAL] = CreateEvent (NULL, FALSE, FALSE, NULL); 
+       
+   if(!res->events[SIGNAL]){
+      DeleteCriticalSection(&((*cond)->waiters_count_lock));
+      free(res);
+      THROW0(system_error,0,"CreateEvent failed for the signals");
+   }
+       
+   /* Create a manual-reset event. */
+   res->events[BROADCAST] = CreateEvent (NULL, TRUE, FALSE,NULL);
+       
+   if(!res->events[BROADCAST]){
+               
+      DeleteCriticalSection(& res->waiters_count_lock);                
+      CloseHandle(res->events[SIGNAL]);
+      free(res); 
+      THROW0(system_error,0,"CreateEvent failed for the broadcasts");
+   }
+
+   return res;
+}
+
+void xbt_thcond_wait(xbt_thcond_t cond, xbt_mutex_t mutex) {
+       
+   unsigned long wait_result;
+   int is_last_waiter;
+
+   /* lock the threads counter and increment it */
+   EnterCriticalSection (& cond->waiters_count_lock);
+   cond->waiters_count++;
+   LeaveCriticalSection (& cond->waiters_count_lock);
+               
+   /* unlock the mutex associate with the condition */
+   LeaveCriticalSection (& mutex->lock);
+       
+   /* wait for a signal (broadcast or no) */
+   wait_result = WaitForMultipleObjects (2, cond->events, FALSE, INFINITE);
+       
+   if(wait_result == WAIT_FAILED)
+     THROW0(system_error,0,"WaitForMultipleObjects failed, so we cannot wait on the condition");
+       
+   /* we have a signal lock the condition */
+   EnterCriticalSection (& cond->waiters_count_lock);
+   cond->waiters_count--;
+       
+   /* it's the last waiter or it's a broadcast ? */
+   is_last_waiter = ((wait_result == WAIT_OBJECT_0 + BROADCAST - 1) && (cond->waiters_count == 0));
+       
+   LeaveCriticalSection (& cond->waiters_count_lock);
+       
+   /* yes it's the last waiter or it's a broadcast
+    * only reset the manual event (the automatic event is reset in the WaitForMultipleObjects() function
+    * by the system. 
+    */
+   if (is_last_waiter)
+      if(!ResetEvent (cond->events[BROADCAST]))
+       THROW0(system_error,0,"ResetEvent failed");
+       
+   /* relock the mutex associated with the condition in accordance with the posix thread specification */
+   EnterCriticalSection (& mutex->lock);
+}
+
+void xbt_thcond_signal(xbt_thcond_t cond) {
+   int have_waiters;
+
+   EnterCriticalSection (& cond->waiters_count_lock);
+   have_waiters = cond->waiters_count > 0;
+   LeaveCriticalSection (& cond->waiters_count_lock);
+       
+   if (have_waiters)
+     if(!SetEvent(cond->events[SIGNAL]))
+       THROW0(system_error,0,"SetEvent failed");
+}
+
+void xbt_thcond_broadcast(xbt_thcond_t cond){
+   int have_waiters;
+
+   EnterCriticalSection (& cond->waiters_count_lock);
+   have_waiters = cond->waiters_count > 0;
+   LeaveCriticalSection (& cond->waiters_count_lock);
+       
+   if (have_waiters)
+     SetEvent(cond->events[BROADCAST]);
+}
+
+void xbt_thcond_destroy(xbt_thcond_t cond){
+   int error = 0;
+   
+   if(!CloseHandle(cond->events[SIGNAL]))
+     error = 1;
+       
+   if(!CloseHandle(cond->events[BROADCAST]))
+     error = 1;
+       
+   DeleteCriticalSection(& cond->waiters_count_lock);
+       
+   xbt_free(cond);
+   
+   if (error)
+     THROW0(system_error,0,"Error while destroying the condition");
+}
+
+#endif