/*
 *  Copyright 2009 OpenSourceStewardshipFoundation.org
 *  Licensed under GNU General Public License version 2
 *
 * Author: seanhalle@yahoo.com
 *
 */

#ifndef _VMS_H
#define	_VMS_H
#define __USE_GNU

#include "VMS_primitive_data_types.h"
#include "Queue_impl/BlockingQueue.h"
#include <pthread.h>

   //This value is the number of hardware threads in the shared memory
   // machine
#define NUM_CORES        4

   // make double-num-cores scheduling slots, plus extra for master
//#define NUM_SCHED_SLOTS  (2 * NUM_CORES + 1)
#define NUM_SCHED_SLOTS  3

   //128K stack.. compromise, want 10K virtPr
#define VIRT_PROCR_STACK_SIZE 0x10000

#define SUCCESS 0

#define writeVMSQ     writePThdQ
#define readVMSQ      readPThdQ
#define makeVMSQ      makePThdQ
#define VMSQueueStruc PThdQueueStruc

//#define thdAttrs NULL  //For PThreads

typedef struct _SchedSlot  SchedSlot;
typedef struct _VMSReqst   VMSReqst;
typedef struct _VirtProcr  VirtProcr;

typedef VirtProcr * (*SlaveScheduler)  ( void * );        //semEnv
typedef void  (*RequestHandler)  ( VirtProcr *, void * ); //prWReqst, semEnv
typedef void  (*VirtProcrFnPtr)  ( void *, VirtProcr * ); //initData, animPr
typedef void    VirtProcrFn      ( void *, VirtProcr * ); //initData, animPr

typedef struct
 {
   void           *endThdPt;
   unsigned int    coreNum;
//   void           *framePtr;
//   void           *stackPtr;
 }
ThdParams;


struct _SchedSlot
 {
   int         workIsDone;
   int         needsProcrAssigned;
   VirtProcr  *procrAssignedToSlot;
 };
//SchedSlot
 
enum ReqstType
 {
   semantic = 1,
   dissipate,
   regCreated,
   IO
 };

struct _VMSReqst
 {
//   VirtProcr   *virtProcrFrom;
   enum ReqstType  reqType;//used for dissipate and in future for IO requests
   void           *semReqData;

   VMSReqst *nextReqst;
 };
//VMSReqst

struct _VirtProcr
 { int         procrID;  //for debugging -- count up each time create
   int         coreAnimatedBy;
   void       *startOfStack;
   void       *stackPtr;
   void       *framePtr;
   void       *nextInstrPt;
   
   void       *coreLoopStartPt;  //allows proto-runtime to be linked later
   void       *coreLoopFramePtr; //restore before jmp back to core loop
   void       *coreLoopStackPtr; //restore before jmp back to core loop

   void       *initialData;

   SchedSlot  *schedSlot;
   VMSReqst   *requests;

   void       *semanticData;
 };
//VirtProcr



typedef struct
 {
   SlaveScheduler   slaveScheduler;
   RequestHandler   requestHandler;
   
   SchedSlot **schedSlots;
   SchedSlot **filledSlots;
   int         numToPrecede;
   
   volatile int stillRunning;
   
   VirtProcr  *masterVirtPr;

   void       *semanticEnv;
   void       *OSEventStruc;    //for future, when add I/O to BLIS

   void       *coreLoopEndPt; //addr to jump to to shut down a coreLoop

   int         setupComplete;
 }
MasterEnv;


//==========================================================

void * coreLoop( void *paramsIn );  //standard PThreads fn prototype
void * coreLoop_Seq( void *paramsIn );  //standard PThreads fn prototype
void masterLoop( void *initData, VirtProcr *masterPr );


//=====================  Global Vars ===================


pthread_t       coreLoopThdHandles[ NUM_CORES ];  //pthread's virt-procr state
ThdParams      *coreLoopThdParams [ NUM_CORES ];
pthread_mutex_t suspendLock;
pthread_cond_t  suspend_cond;

volatile MasterEnv      *_VMSMasterEnv;

   //workQ is global, static, and volatile so that core loop has its location
   // hard coded, and reloads every time through the loop -- that way don't
   // need to save any regs used by core loop
volatile VMSQueueStruc  *_VMSWorkQ;

//==========================
void
VMS__init();

void
VMS__init_Seq();

void
VMS__start_the_work_then_wait_until_done();

void
VMS__start_the_work_then_wait_until_done_Seq();

VirtProcr *
VMS__create_procr( VirtProcrFnPtr fnPtr, void *initialData );

VirtProcr *
VMS__create_the_shutdown_procr();

//==========================
inline void
VMS__add_sem_request( void *semReqData, VirtProcr *callingPr );

void
VMS__send_register_new_procr_request( VirtProcr *newPrToRegister,
                                      VirtProcr *reqstingPr );

void
VMS__free_request( VMSReqst *req );

void
VMS__remove_and_free_top_request( VirtProcr *reqstingPr );

VMSReqst *
VMS__take_top_request_from( VirtProcr *reqstingPr );

inline void *
VMS__take_sem_reqst_from( VMSReqst *req );

inline int
VMS__isSemanticReqst( VMSReqst *req );

inline int
VMS__isDissipateReqst( VMSReqst *req );

inline int
VMS__isCreateReqst( VMSReqst *req );

//==========================

void
VMS__suspend_procr( VirtProcr *callingPr );

void
VMS__dissipate_procr( VirtProcr *prToDissipate );

void
VMS__handle_dissipate_reqst( VirtProcr *procrToDissipate );

void
VMS__cleanup_after_shutdown();

//============================= Statistics ==================================

typedef unsigned long long TSCount;

   //Frequency of TS counts
   //TODO: change freq for each machine
#define TSCOUNT_FREQ 3180000000

#define saveTimeStampCountInto(low, high) \
   asm volatile("RDTSC;                   \
                 movl %%eax, %0;          \
                 movl %%edx, %1;"         \
   /* outputs */ : "=m" (low), "=m" (high)\
   /* inputs  */ :                        \
   /* clobber */ : "%eax", "%edx"         \
                );

inline TSCount getTSCount();

//===================== Debug ==========================
int numProcrsCreated;


#endif	/* _VMS_H */

