Subversion Repositories HomeAutomation

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

/***************************************************************************
                           wthread.c  -  description
                              -------------------
     begin                : Sun Jan 02 2000
     copyright            : (C) 2001 by Rainer Lehrig
     email                : lehrig@t-online.de
  ***************************************************************************/
 
 /***************************************************************************
  *                                                                         *
  *   This library is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as        *
  *   published by the Free Software Foundation                             *
  *                                                                         *
  ***************************************************************************/
 /***********************************************************************************
 
 Wrapper for posix threads (UNIX,VMS,windows)
 
 (C) Rainer Lehrig 2000                                       lehrig@t-online.de
 
 ***********************************************************************************/
 #include <errno.h>
 #include "rlwthread.h"
 #ifdef unix
 #include <sys/time.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netdb.h>
 #include <pthread.h>
 #endif
 
 /***************************************/
 /* init attributes with default values */
 /***************************************/
 int rlwthread_attr_init(pthread_attr_t *attr)
 {
 #ifdef _WIN32
   memset(attr,0,sizeof(pthread_attr_t));
   return 0;
 #else
   return pthread_attr_init(attr);
 #endif
 }
 
 /* #pdoku headerlevel 2 ^^wthread_create */
 /*******************************************/
 /* create a thread                         */
 /* tid:  returned thread_id                */
 /* attr: thread creation attributes        */
 /* func: thread start routine              */
 /* arg:  parameter to thread start routine */
 /*******************************************/
 int rlwthread_create(pthread_t *tid, const pthread_attr_t *attr,
                       void *(*func)(void*), void *arg)
 {
 #ifdef _WIN32
   HANDLE handle;
   int ThreadId;
   int dwStackSize = 0;
   if(attr != NULL) dwStackSize = attr->__stacksize;
   handle = CreateThread( NULL,                    /* pointer to thread security attributes */
                          dwStackSize,             /* initial thread stack size, in bytes   */
  (LPTHREAD_START_ROUTINE)func,                    /* pointer to thread function            */
                          arg,                     /* argument for new thread               */
                          0,                       /* creation flags                        */
        (unsigned long *) &ThreadId                /* pointer to returned thread identifier */
                        );
   *tid = (pthread_t) handle;
   if(handle == NULL) return -1;
   else               return 0;
 #else
   return pthread_create(tid,attr,func,arg);
 #endif
 }
 
 void rlwthread_close_handle(pthread_t *tid)
 {
 #ifdef _WIN32
   CloseHandle((HANDLE) *tid);
 #else
   if(tid == NULL) return;
 #endif
 }
 
 /**************************************************************/
 /* terminate a thread                                         */
 /* call this function within a thread to terminate the thead  */
 /* or return from the thread start routine                    */
 /* status: return value from the thread (see wthread_join)    */
 /**************************************************************/
 void rlwthread_exit(void *status)
 {
 #ifdef _WIN32
   DWORD *ptr;
   ptr = (DWORD *) status;
   if(status == NULL) ExitThread((DWORD) 0);
   else               ExitThread(*ptr);
 #else
   pthread_exit(status);
 #endif
 }
 
 /* #pdoku headerlevel 2 ^^wthread_join */
 /************************************/
 /* wait for termination of thread   */
 /* tid:    thread id                */
 /* status: return value from thread */
 /************************************/
 int rlwthread_join(pthread_t tid, void **status)
 {
 #ifdef _WIN32
   DWORD exitcode;
   while(1)
   {
     GetExitCodeThread((HANDLE) tid,&exitcode);
     if(exitcode != STILL_ACTIVE) return exitcode;
     Sleep(10); /* sleep 10 msec */
   }
 #else
   return pthread_join(tid,status);
 #endif
 }
 
 /**************************/
 /* init a mutex           */
 /* mptr: pointer to mutex */
 /* atrr: mutex atrributes */
 /**************************/
 int rlwthread_mutex_init(pthread_mutex_t *mptr,
                           const pthread_mutexattr_t *attr)
 {
 #ifdef _WIN32
   HANDLE handle = CreateMutex(NULL, FALSE, NULL);
   if(handle) *mptr = handle;
   //old InitializeCriticalSection(mptr);
   return 0;
 #else
   return pthread_mutex_init(mptr,attr);
 #endif
 }
 
 /**************************/
 /* destroy a mutex        */
 /* mptr: pointer to mutex */
 /**************************/
 int rlwthread_mutex_destroy(pthread_mutex_t *mptr)
 {
 #ifdef _WIN32
   CloseHandle(*mptr);
   //old DeleteCriticalSection(mptr);
   return 0;
 #else
   return pthread_mutex_destroy(mptr);
 #endif
 }
 
 /**************************/
 /* lock a mutex           */
 /* mptr: pointer to mutex */
 /**************************/
 int rlwthread_mutex_lock(pthread_mutex_t *mptr)
 {
 #ifdef _WIN32
   if(WaitForSingleObject(*mptr, INFINITE) == WAIT_OBJECT_0) return 0;
   //old EnterCriticalSection(mptr); // pointer to critical section object
   return 0;
 #else
   return pthread_mutex_lock(mptr);
 #endif
 }
 
 /********************************/
 /* try to lock a mutex          */
 /* mptr: pointer to mutex       */
 /* return 0 if already locked   */
 /* return !0 if lock sucessfull */
 /********************************/
 
 #ifdef _WIN32
 WINBASEAPI BOOL WINAPI TryEnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection);
 #endif
 
 int rlwthread_mutex_trylock(pthread_mutex_t *mptr)
 {
 #ifdef _WIN32
   DWORD ret;
 
   ret = WaitForSingleObject(*mptr, 0);
   if(ret == WAIT_OBJECT_0) return 1;
   return 0;
   //old ret = TryEnterCriticalSection(mptr); // pointer to critical section object
   return ret;
 #else
   int ret;
 
   ret = pthread_mutex_trylock(mptr);
   if(ret == EBUSY) return 0;
   return 1;
 #endif
 }
 
 /**************************/
 /* unlock a mutex         */
 /* mptr: pointer to mutex */
 /**************************/
 int rlwthread_mutex_unlock(pthread_mutex_t *mptr)
 {
 #ifdef _WIN32
   ReleaseMutex(*mptr);
   //old LeaveCriticalSection(mptr);
   return 0;
 #else
   return pthread_mutex_unlock(mptr);
 #endif
 }
 
 /**************************/
 /* kill a thread          */
 /* tid handel of thread   */
 /**************************/
 int rlwthread_cancel(pthread_t tid)
 {
 #ifdef _WIN32
   return (int) CloseHandle((HANDLE) tid);
 #else
   return pthread_cancel(tid);
 #endif
 }
 
 /***********************************************/
 /* initialize a semaphore                      */
 /* s is a pointer to a WSEMAPHORE struct       */
 /* cmax is the maximum number of the semaphore */
 /* return 0                                    */
 /***********************************************/
 int rlwrapinit_semaphore(WSEMAPHORE *s, int cmax)
 {
 /* Create a semaphore with initial count=0 max. counts of cmax. */
 #ifdef _WIN32
 
   s->cmax = cmax;
   s->hSemaphore = CreateSemaphore(
     NULL,   /* no security attributes */
     0,      /* initial count */
     cmax,   /* maximum count */
     NULL);  /* unnamed semaphore */
 
   if(s->hSemaphore == NULL) return -1; /* Check for error. */
   return 0;
 
 #else
 
   s->cmax   = cmax;
   s->nready = 0;
   rlwthread_mutex_init(&s->mutex, NULL);
   pthread_cond_init(&s->cond, NULL);
   return 0;
 
 #endif
 }
 
 int rlwrapdestroy_semaphore(WSEMAPHORE *s)
 {
 #ifdef _WIN32
   CloseHandle(s->hSemaphore);
 #else
   rlwthread_mutex_destroy(&s->mutex);
 #endif
   return 0;
 }
 
 /***********************************************************************/
 /* increment a semaphore                                               */
 /* s is a pointer to a WSEMAPHORE struct                               */
 /* the producer will call this function whenever new data is available */
 /* return 0=OK -1=error                                                */
 /***********************************************************************/
 int rlwrapincrement_semaphore(WSEMAPHORE *s)
 {
 /* Increment the count of the semaphore. */
 #ifdef _WIN32
 
   if(!ReleaseSemaphore(
         s->hSemaphore,  /* handle of semaphore */
         1,              /* increase count by one */
         NULL) )         /* not interested in previous count */
   {
     return -1; /* Deal with the error. */
   }
   return 0;
 
 #else
 
   pthread_mutex_lock(&s->mutex);
   if(s->nready == 0) pthread_cond_signal(&s->cond);
   s->nready++;
   pthread_mutex_unlock(&s->mutex);
   return 0;
 
 #endif
 }
 
 /*********************************************************************************/
 /* wait for a semaphore                                                          */
 /* s is a pointer to a WSEMAPHORE struct                                         */
 /* the consumer will call this function to wait for new data to become available */
 /* return 0                                                                      */
 /*********************************************************************************/
 int rlwrapwait_semaphore(WSEMAPHORE *s)
 {
 #ifdef _WIN32
 
   int ret;
   ret = WaitForSingleObject(
         s->hSemaphore,   /* handle of semaphore */
         INFINITE);       /* infinite time-out interval */
   if(ret) return 0;
   return 0;
 
 #else
 
   pthread_mutex_lock(&s->mutex);
   while(s->nready == 0)
   {
     pthread_cond_wait(&s->cond,&s->mutex);
   }  
   s->nready--;
   pthread_mutex_unlock(&s->mutex);
   return 0;
 
 #endif
 }
 
 int rlwthread_sleep(long msec)
 {
 #ifdef _WIN32
   Sleep(msec);
   return 0;
 #endif
 
 #ifdef unix
   fd_set wset,rset,eset;
   struct timeval timeout;
 
   FD_ZERO(&rset);
   FD_ZERO(&wset);
   FD_ZERO(&eset);
   timeout.tv_sec  = msec / 1000;
   timeout.tv_usec = (msec % 1000) * 1000;
   select(1,&rset,&wset,&eset,&timeout);
   return 0;
 #endif
 
 #ifdef __VMS
   struct timespec interval;
 
   interval.tv_sec  =  msec / 1000;
   interval.tv_nsec = (msec % 1000) * 1000 * 1000; /* wait msec msec */
   pthread_delay_np(&interval);
   return 0;
 #endif
 }
 
 void rlsleep(long msec)
 {
   rlwthread_sleep(msec);
 }
 /*** test routine ***/
 /**************************************************************/
 /* This is an example how to use the wthread_xxx functions    */
 /**************************************************************/
 #define TESTINGx
 #ifdef  TESTING
 #include "stdio.h"
 #include "stdlib.h"
 #ifndef _WIN32
 #include "unistd.h"
 #endif
 
 /******************************************/
 /* here we define 2 mutexes (semaphores)  */
 /* the mutexes are global two all threads */
 /******************************************/
 pthread_mutex_t mutex1, mutex2;
 WSEMAPHORE semaphore;
 
 /************************************************************************/
 /* this is the tread function                                           */
 /* it's name is given as parameter to wthread_create                    */
 /* *arg is an argument given by the last parameter of wthread_create    */
 /* you can get the return value by pthread_join (status)                */
 /************************************************************************/
 void *thread(void *arg)
 {
   int i=0;
   printf("thread start : %s\n",(const char *) arg);
   while(i++ < 50)
   {
     rlwrapwait_semaphore(&semaphore);
     printf("thread %d\n",i);
     /* sleep(1); */
   }
   return NULL;
 }
 
 int main()
 {
   pthread_t tid; /* this is the thread_id */
   void *status;  /* this is the return value of the tread */
   int i;
 
   /*****************************************************************************/
   /* here we initialize 2 mutexes                                              */
   /* the mutexes are defined global to all threads                             */
   /* for compatibility with MSWINDOWS the second parameter should be NULL      */
   /*                                                                           */
   /* in order to mark critical sections we can now use the following functions */
   /* wthread_mutex_lock                                                        */
   /* wthread_mutex_unlock                                                      */
   /* if a mutex is locked by a thread and an other thread is calling           */
   /* wthread_mutex_lock it will be blocked until the first thread calls        */
   /* the wthread_mutex_unlock function                                         */
   /*                                                                           */
   /* this function is the reverse of wthread_mutex_init                        */
   /* wthread_mutex_destroy                                                     */
   /*****************************************************************************/
   rlwthread_mutex_init(&mutex1, NULL);
   rlwthread_mutex_init(&mutex2, NULL);
 
   rlwrapinit_semaphore(&semaphore, 1000);
   printf("create a thread\n");
   /****************************************************************/
   /* this call will create a new thread                           */
   /* tid is the returned thread_id                                */
   /*     you can use this id for example in wthread_join          */
   /* in this example the second parameter is NULL                 */
   /*     you can call wthread_attr_init(pthread_attr_t *attr)     */
   /*     to initialize the start attributes                       */
   /*     pthread_attr_t attr;                                     */
   /*     wthread_attr_init(&attr);                                */
   /*     wthread_create(&tid, &attr, thread, "hello thread");     */
   /* thread is the name of the thread function (see above)        */
   /* the last parameter is given to the thread function           */
   /****************************************************************/
   rlwthread_create(&tid, NULL, thread, "hello thread");
 
   i=0;
   while(i++ < 50)
   {
     printf("main %d\n",i);
     rlwrapincrement_semaphore(&semaphore);
     if(i%4 == 0) Sleep(10);
   }
 
   printf("waiting for thread\n");
   /*****************************************************/
   /* this call waits for the termination of thread tid */
   /* the return value of the thread is given to status */
   /*****************************************************/
   rlwthread_join(tid, &status);
   printf("finish\n");
   return 0;
 }
 #endif