thread.c 3.23 KB
#include <setjmp.h>
#include <signal.h>
#include <time.h>
#include <errno.h>

#include <scot/thread.h>
#include <scot/exception.h>
#include <scot/scot_int.h>
#include <scot/memory.h>

struct join_cond_st
{
   pthread_mutex_t join_alarm_mutex;
   pthread_cond_t  join_alarm_cond;
   THREAD_T        thread;
};

static
T_PROC_RET 
join_thread (void * arg)
{
   int                   status;
   struct join_cond_st * join_cond = (struct join_cond_st *) arg;

   THREAD_CANCEL_ENABLE;
   THREAD_CANCEL_ASYNC;

   pthread_join (join_cond->thread, NULL);

   status = pthread_cond_signal (&(join_cond->join_alarm_cond));
   if (status != 0)
   {
      perror ("problem with sending signal within join");
   }

   return NULL;
}

THREAD_T
thread_new (T_PROC_RET (*t_proc)(void *), void* arg)
{
	THREAD_T handle;

   if (pthread_create (&handle, NULL, t_proc, arg) != 0)
   {
      SCOT_MEM_ZERO (&handle, sizeof (THREAD_T));
   }

	return handle;
}

void
thread_end (THREAD_T thread, uint32_t timeout)
{
	int err;

	err = CANCEL_THREAD (thread);
	if (err != 0)
		THROW (EXC (EXC_ERROR, 
					err, 
					"[EVENT_SOURCE_THREAD]cancel request failed"));

	err = JOIN_THREAD (thread, timeout);
	if (err == JOIN_TIMEOUT)
		THROW (EXC (EXC_ERROR,
					err,
					"[EVENT_SOURCE_THREAD]timeout exceeded while waiting "
					"for threads end"));
	if (err == JOIN_ERROR)
		THROW (EXC (EXC_ERROR,
					err,
					"[EVENT_SOURCE_THREAD]failure on waiting for threads end"));
}

int
thread_join (THREAD_T thread, uint32_t timeout)
{
   int                 status,
                       join_state  = JOIN_OK;
   struct timespec     alarm;
   pthread_t           join_thr;
   struct join_cond_st join_cond =
   {
      PTHREAD_MUTEX_INITIALIZER,
      PTHREAD_COND_INITIALIZER,
      thread
   };

   if (timeout == INFINITE)
   {
      if (pthread_join (thread, NULL) == 0)
      {
         return JOIN_OK;
      }
      else
      {
         return JOIN_ERROR;
      }
   }

   alarm.tv_sec  = time (NULL) + timeout;
   alarm.tv_nsec = 0;

   status = pthread_mutex_lock (&join_cond.join_alarm_mutex);
   if (status != 0)
   {
      perror ("problem achiving mutex within join");
   }

   join_thr = NEW_THREAD (join_thread, (void *) &join_cond);

   status = pthread_cond_timedwait (
         &(join_cond.join_alarm_cond), 
         &(join_cond.join_alarm_mutex),
         &alarm);
   if (status != 0)
   {
      if (status == ETIMEDOUT) 
      {
         join_state = JOIN_TIMEOUT;

         pthread_cancel (join_thr);
         pthread_join   (join_thr, NULL);
      }
      else
      {
         perror ("problem with condition wait within join");
      }
   }

   return join_state;
}

void
thread_mutex_new (THREAD_MUTEX_T * mutex)
{
   pthread_mutex_init (mutex, NULL);
}

void
thread_cond_new (THREAD_COND_T * cond)
{
   pthread_cond_init (cond, NULL);
}

int
thread_mutex_lock (THREAD_MUTEX_T * mutex)
{
   if (pthread_mutex_lock (mutex) == 0)
   {
      return MUTEX_LOCK_OK;
   }
   else
   {
      return MUTEX_LOCK_ERROR;
   }
}

int
thread_cond_wait  (THREAD_COND_T * cond, THREAD_COND_CS_T * cs, uint32_t t)
{
	if (t == INFINITE)
		return pthread_cond_wait (cond, cs);
	else
	{
		struct timespec tout;

		tout.tv_sec  = time (NULL) + t;
		tout.tv_nsec = 0;

		return pthread_cond_timedwait (cond, cs, &tout);
	}
}