/* 
 * $Id: ompclib.h,v 1.42 2002/10/08 13:44:37 a-hasega Exp $
 * $RWC_Release: Omni-1.6 $
 * $RWC_Copyright:
 *  Omni Compiler Software Version 1.5-1.6
 *  Copyright (C) 2002 PC Cluster Consortium
 *  
 *  This software is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License version
 *  2.1 published by the Free Software Foundation.
 *  
 *  Omni Compiler Software Version 1.0-1.4
 *  Copyright (C) 1999, 2000, 2001.
 *   Tsukuba Research Center, Real World Computing Partnership, Japan.
 *  
 *  Please check the Copyright and License information in the files named
 *  COPYRIGHT and LICENSE under the top  directory of the Omni Compiler
 *  Software release kit.
 *  
 *  
 *  $
 */
/* RWC Omni OpenMP C compiler runtime lib. header */

#ifndef _OMPC_THREAD_H
#define _OMPC_THREAD_H

#define USE_LOG 1

#define TRUE 1
#define FALSE 0

#include "exc_platform.h"
#include "ompc_reduction.h"

#ifdef OMNI_OS_CYGWIN32
# define SIMPLE_SPIN
#endif /* OMNI_OS_CYGWIN32 */

#ifdef USE_PTHREAD	/* pthread: set gcc include path to 2.6(pdph3) */
# include <pthread.h>
# ifndef OMNI_OS_CYGWIN32
#  include <sched.h>
# endif /* !OMNI_OS_CYGWIN32 */
typedef pthread_t _ompc_proc_t;
# if 0
#  define _OMPC_WAIT(cond)	while(cond) sched_yield()
# else
#  define MAX_COUNT 10000
#  ifdef SIMPLE_SPIN
#   define _YIELD_ME_ sleep(0)
#  else
#   define _YIELD_ME_ sched_yield()
#  endif /* SIMPLE_SPIN */
#  define _OMPC_WAIT(cond) \
	{ \
	  if (cond) { \
	    volatile int c = 0; \
	    while (cond) { \
	      if (c++ > MAX_COUNT) { \
                _YIELD_ME_; \
		c = 0; \
	      } \
	    } \
	  } \
	}
# endif /* 0 */
# define _OMPC_PROC_SELF		pthread_self()
#endif /* USE_PTHREAD */

#ifdef USE_SOL_THREAD	/* solaris thread */
#ifndef _REENTRANT
#define _REENTRANT
#endif /* !_REENTRANT */
#include <sys/types.h>
#include <thread.h>
#include <synch.h>
#include <sys/processor.h>
#include <sys/procset.h>
typedef thread_t _ompc_proc_t;
#ifdef not
#define _OMPC_WAIT(cond)	while(cond) thr_yield()
#else
#define MAX_COUNT 10000
#define _OMPC_WAIT(cond)\
{if(cond){ volatile int c = 0; while(cond){ if(c++>MAX_COUNT){ thr_yield(); c = 0; }}}}
#endif
#define _OMPC_PROC_SELF		thr_self()
#endif

#if defined(USE_SPROC) && defined(OMNI_OS_IRIX)
#ifndef NO_RESOURCE_H
#include <sys/resource.h>
#endif /* !NO_RESOURCE_H */
#include <sys/prctl.h>
#include <signal.h>
#include <ulocks.h>
typedef pid_t _ompc_proc_t;
#ifdef not
#define _OMPC_WAIT(cond)        while(cond) sched_yield()
#else
#define MAX_COUNT 10000
#define _OMPC_WAIT(cond)\
{if(cond){ volatile int c = 0; while(cond){ if(c++>MAX_COUNT){ sched_yield(); c = 0; }}}}
#endif
#define _OMPC_PROC_SELF         getpid()
#endif /* USE_SPROC && OMNI_OS_IRIX */

#ifdef USE_SPIN_LOCK
typedef int _ompc_lock_t;
#else
# ifdef USE_PTHREAD
typedef pthread_mutex_t _ompc_lock_t;
# endif
# ifdef USE_SOL_THREAD
typedef mutex_t _ompc_lock_t;
# endif
#endif

typedef struct {
  _ompc_lock_t	lock, wait;
  _ompc_proc_t	id;
  int		count;
} _ompc_nest_lock_t;

#define N_PROC_DEFAULT 4  	/* default */
#define MAX_PROC 256
#ifdef OMNI_CPU_MIPS
#define CACHE_LINE_SIZE	128
#else
#define CACHE_LINE_SIZE	32
#endif /* OMNI_CPU_MIPS */

#ifdef USE_SPROC
typedef void (*cfunc)();
#else
typedef void* (*cfunc)();
#endif

extern volatile int _ompc_nested;	/* nested enable/disable */
extern volatile int _ompc_dynamic;	/* dynamic enable/disable */
extern volatile int _ompc_max_threads;	/* max number of thread */
extern int _ompc_n_proc;

/* OMP processor structure */
struct ompc_proc {
    _ompc_proc_t pid;		/* thread id give by [p]thread_self() */
    unsigned int pe;
    struct ompc_proc *link;	/* hash link */
    struct ompc_proc *next;	/* link */
    struct ompc_thread *thr;	/* thr != NULL, running */
    struct ompc_thread *free_thr;
    int is_used;		/* allocated or not */
};

struct ompc_thread {
    struct ompc_thread *parent;		/*  */
    struct ompc_thread *freelist;	/* freelist next */
    int num;		/* the thread number of this thread in team */
    int num_thds;	/* current running thread, refenced by children */
    int in_parallel;	/* current thread executes the region in parellel */
    cfunc func;
    void *args;

    /* used for 'sections' */
    int section_id; 
    int last_section_id;

    /* used for schedule */
    int loop_chunk_size;
    int loop_end;
    int loop_sched_index;
    int loop_stride;		  /* used for static scheduling */
    volatile int dynamic_index;	  /* shared in children */

    int loop_id;
    volatile int ordered_id;	/* shared in team */
    volatile int ordered_step;  /* shared in team */

    /* for 'lastprivate' */
    int is_last;

    /* sync for shared data, used for 'single' directive */
    /* shared by children */
    volatile struct {
	int _v;
	char _padding[CACHE_LINE_SIZE-sizeof(int)];
    } in_flags[MAX_PROC];
    volatile int in_count;
    volatile int out_count;

    /* structure for barrier in this team */
    volatile int barrier_sense;
    volatile struct barrier_flag {
	int _v;
	any_type r_v;  /* for reduction */
	char _padding[CACHE_LINE_SIZE-sizeof(int)-sizeof(any_type)];
    } barrier_flags[MAX_PROC];
};

/* library prototypes */
void _ompc_init(int argc,char *argv[]);
void _ompc_init_proc_num(int);
void _ompc_do_parallel(cfunc f,void *args);
void _ompc_finalize(void);
void _ompc_fatal(char *msg);
void _ompc_terminate (int);

void _ompc_init_lock(_ompc_lock_t *);
void _ompc_lock(volatile _ompc_lock_t *);
void _ompc_unlock(volatile _ompc_lock_t *);
void _ompc_destroy_lock(volatile _ompc_lock_t *);
int _ompc_test_lock(volatile _ompc_lock_t *);
void _ompc_init_nest_lock(_ompc_nest_lock_t *);
void _ompc_nest_lock(volatile _ompc_nest_lock_t *);
void _ompc_nest_unlock(volatile _ompc_nest_lock_t *);
void _ompc_destroy_nest_lock(volatile _ompc_nest_lock_t *);
int _ompc_test_nest_lock(volatile _ompc_nest_lock_t *);
void _ompc_thread_barrier(int i, struct ompc_thread *tp);

void _ompc_atomic_init_lock ();
void _ompc_atomic_lock ();
void _ompc_atomic_unlock ();
void _ompc_atomic_destroy_lock ();

void _ompc_critical_init ();
void _ompc_critical_destroy ();
void _ompc_enter_critical (_ompc_lock_t **);
void _ompc_exit_critical (_ompc_lock_t **);

void _ompc_set_runtime_schedule(char *s);

#ifndef OMNI_CPU_ALPHA
#ifndef __GNUC__
#ifndef __PGI
# define asm(X) __asm(X)
#endif /* __PGI */
#else /* __GNUC__ */
# define asm(X) __asm volatile (X)
#endif /* __GNUC__ */
#endif

#ifdef OMNI_CPU_I386
# define MBAR() { /* asm("cpuid"); */ }
#else
# ifdef OMNI_CPU_SPARC
#  define MBAR() asm("stbar")
# else
#  ifdef OMNI_CPU_ALPHA
extern void	__alpha_mbar _ANSI_ARGS_((void));
#   define MBAR() __alpha_mbar()
#  else
#   define MBAR() /**/
#  endif /* OMNI_CPU_ALPHA */
# endif /* OMNI_CPU_SPARC */
#endif /* OMNI_CPU_I386 */

extern int _ompc_debug_flag;

extern int _ompc_in_parallel (struct ompc_thread *);
extern int _ompc_get_num_threads (struct ompc_thread *);

#ifdef USE_LOG
extern int _ompc_log_flag;
void tlog_init(char *name);
void tlog_slave_init(void);
void tlog_finalize(void);
void tlog_parallel_IN(int id);
void tlog_parallel_OUT(int id);
void tlog_barrier_IN(int id);
void tlog_barrier_OUT(int id);
void tlog_loop_init_EVENT(int id);
void tlog_loop_next_EVENT(int id);
void tlog_section_EVENT(int id);
void tlog_single_EVENT(int id);
void tlog_critial_IN(int id);
void tlog_critial_OUT(int id);
#endif

#endif /* _OMPC_THREAD_H */


