/*
 * POSIX.1 Signals
 *
 * Written by J. Vidal
 * Copyright (C) Dec, 2002 OCERA Consortium.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2.
 *
 * Simple program showing a nasty mutex bug when setting 
 * t->do_abort=0 on do_signal.
 *
 */

#include <rtl.h>
#include <rtl_mutex.h>
#include <rtl_sched.h>

static pthread_t mutex_owner, blocked_thread;
static pthread_mutex_t mut;

static void *mutex_owner_routine(void *arg)
{
  struct sched_param p;
  int err=0,i=0;
  
  p . sched_priority =1;
  pthread_setschedparam (pthread_self(), SCHED_FIFO, &p);
  
  rtl_printf("MUTEX OWNER. Just before adquiring the mutex.\n");
  pthread_mutex_lock(&mut);
  rtl_printf(" \n\n MUTEX OWNER - Mutual exclusion code.\n");
  rtl_printf("MUTEX_OWNER - Testing mutexes --> sending signals RTL_SIGNAL_SUSPEND & RTL_SIGNAL_WAKEUP\n\n");
  // wait for the other task to get blocked.
  usleep(1000);
  
  err=pthread_wakeup_np(blocked_thread);
  rtl_printf("pthread_wakeup_np(thread[blocked_thread]) returns %d\n",err);
  err=pthread_suspend_np(blocked_thread);
  rtl_printf("pthread_suspend_np(blocked_thread) returns %d\n",err); 
  err=pthread_wakeup_np(blocked_thread);
  rtl_printf("pthread_wakeup_np(thread[blocked_thread]) returns %d\n",err);
  
  rtl_printf("MUTEX OWNER. BEFORE pthread_mutex_unlock \n");
  err=pthread_mutex_unlock(&mut);
  rtl_printf("MUTEX OWNER. pthread_mutex_unlock returned %d. errno %d\n",err,errno);
  
  rtl_printf("MUTEX OWNER about to end \n");
  return (void *)err;
}

static void *blocked_thread_routine(void *arg)
{
  int err=0;
  struct sched_param p;
  
  p . sched_priority =1;
  pthread_setschedparam (pthread_self(), SCHED_FIFO, &p);
  
  
  rtl_printf("BLOCKED THREAD. Just before adquiring the mutex.\n");
  pthread_mutex_lock(&mut);
  rtl_printf(" \n\n BLOCKED THREAD - Mutual exclusion code.\n");
  rtl_printf("BLOCKED THREAD. BEFORE pthread_mutex_unlock \n");
  err=pthread_mutex_unlock(&mut);
  rtl_printf("BLOCKED THREAD. pthread_mutex_unlock returned %d. errno %d\n",err,errno);
  
  rtl_printf("BLOCKED THREAD about to end \n");
  return (void *)err;
}

int init_module(void) {
  pthread_attr_t attr;
  pthread_mutexattr_t mutattr;
  
  pthread_mutexattr_init(&mutattr); 
  /*    pthread_mutexattr_settype(&mutattr,PTHREAD_MUTEX_SPINLOCK_NP); */
  
  pthread_mutex_init(&mut,&mutattr);  
  
  pthread_attr_init(&attr);
  // Threads creation.
  pthread_create (&mutex_owner, &attr, mutex_owner_routine,(void *) 0); 
  pthread_create (&blocked_thread, &attr, blocked_thread_routine,(void *) 0); 
  
 return 0;
}

void cleanup_module(void) {
  void *retval;


    pthread_join (mutex_owner, &retval);
    rtl_printf("pthread_join on MUTEX OWNER returned %d\n", (int) retval);
    pthread_join (blocked_thread, &retval);
    rtl_printf("pthread_join on BLOCKED THREAD returned %d\n", (int) retval);
   
    
    //pthread_delete_np(thread[i]);

  pthread_mutex_destroy(&mut);      
  
}
