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

#ifndef _VMS_H
#define	_VMS_H
#define _GNU_SOURCE

#include "VMS_primitive_data_types.h"
#include "DynArray/DynArray.h"
#include "Hash_impl/PrivateHash.h"
#include "Histogram/Histogram.h"
#include "Queue_impl/PrivateQueue.h"
#include "vmalloc.h"

#include <pthread.h>
#include <sys/time.h>

//=================  Defines: included from separate files  =================
//
// Note: ALL defines are in other files, none are in here
//
#include "Defines/VMS_defs__main.h"


//================================ Typedefs =================================
//
typedef unsigned long long TSCount;
typedef union
 { uint32 lowHigh[2];
   uint64 longVal;
 }
TSCountLowHigh;

typedef struct _SchedSlot     SchedSlot;
typedef struct _VMSReqst      VMSReqst;
typedef struct _SlaveVP       SlaveVP;
typedef struct _MasterVP      MasterVP;
typedef struct _IntervalProbe IntervalProbe;
typedef struct _GateStruc     GateStruc;


typedef SlaveVP * (*Sched_Assigner) ( void *, int       ); //semEnv, coreIdx
typedef void      (*RequestHandler) ( SlaveVP *, void * ); //prWReqst, semEnv
typedef void      (*TopLevelFnPtr)  ( void *, SlaveVP * ); //initData, animSlv
typedef void        TopLevelFn      ( void *, SlaveVP * ); //initData, animSlv
typedef void      (*ResumeSlvFnPtr) ( SlaveVP *, void * );

//============================ HW Dependent Fns ================================

#include "VMS__HW_dependent.h"

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

inline TSCount getTSCount();

//============= Request Related ===========
//

enum VMSReqstType   //avoid starting enums at 0, for debug reasons
 {
   semantic = 1,
   createReq,
   dissipate,
   VMSSemantic      //goes with VMSSemReqst below
 };

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

   VMSReqst *nextReqst;
 };
//VMSReqst

enum VMSSemReqstType   //These are equivalent to semantic requests, but for
 {                     // VMS's services available directly to app, like OS
   createProbe = 1,    // and probe services -- like a VMS-wide built-in lang
   openFile,
   otherIO
 };

typedef struct
 { enum VMSSemReqstType reqType;
   SlaveVP           *requestingSlv;
   char                *nameStr;  //for create probe
 }
 VMSSemReq;


//====================  Core data structures  ===================

struct _SchedSlot
 {
   int         workIsDone;
   int         needsSlaveAssigned;
   SlaveVP  *slaveAssignedToSlot;
 };
//SchedSlot

/*WARNING: re-arranging this data structure could cause Slv switching
 *         assembly code to fail -- hard-codes offsets of fields
 */
struct _SlaveVP
 { int         slaveID;  //each slave given a unique ID
   int         coreAnimatedBy;
   void       *startOfStack;
   void       *stackPtr;
   void       *framePtr;
   void       *resumeInstrPtr;
   
   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

   SchedSlot  *schedSlot;
   VMSReqst   *requests;

   void       *semanticData; //this is live for the life of Slv
   void       *dataRetFromReq;//Used to return vals from plugin to Wrapper Lib

      //=========== MEASUREMENT STUFF ==========
       MEAS__Insert_Meas_Fields_into_Slave;
      //========================================
   
   float64      createPtInSecs;  //have space but don't use on some configs
 };
//SlaveVP


/*WARNING: re-arranging this data structure could cause Slv-switching
 *         assembly code to fail -- hard-codes offsets of fields
 *         (because -O3 messes with things otherwise)
 */
typedef struct
 {
   Sched_Assigner   slaveAssigner;
   RequestHandler   requestHandler;
   
   SchedSlot     ***allSchedSlots;
   VMSQueueStruc  **readyToAnimateQs;
   SlaveVP        **masterVPs;

   void            *semanticEnv;
   void            *OSEventStruc;   //for future, when add I/O to BLIS
   MallocArrays   *freeLists;
   int32            amtOfOutstandingMem; //total currently allocated

   void            *coreLoopReturnPt;//addr to jump to to re-enter coreLoop

   int32            setupComplete;
   int32            numMasterInARow[NUM_CORES];//detect back-to-back masterVP
   int32            masterLock __align_to_cacheline__;
   GateStruc       *workStealingGates[ NUM_CORES ]; //concurrent work-steal
   int32            workStealingLock;
   
   int32            numSlavesCreated; //gives ordering to processor creation
   int32            numSlavesAlive;   //used to detect when to shutdown

      //=========== MEASUREMENT STUFF =============
       IntervalProbe   **intervalProbes;
       PrivDynArrayInfo *dynIntervalProbesInfo;
       HashTable        *probeNameHashTbl;
       int32             masterCreateProbeID;
       float64           createPtInSecs;
       Histogram       **measHists;
       PrivDynArrayInfo *measHistsInfo;
       MEAS__Insert_Susp_Meas_Fields_into_MasterEnv;
       MEAS__Insert_Master_Meas_Fields_into_MasterEnv;
       MEAS__Insert_Master_Lock_Meas_Fields_into_MasterEnv;
       MEAS__Insert_Malloc_Meas_Fields_into_MasterEnv;
       MEAS__Insert_Plugin_Meas_Fields_into_MasterEnv;
       MEAS__Insert_System_Meas_Fields_into_MasterEnv;
      //==========================================
 }
MasterEnv;

//=========================  Extra Stuff Data Strucs  =======================
typedef struct
 {

 }
VMSExcp;

struct _GateStruc
 {
   int32 gateClosed;
   int32 preGateProgress;
   int32 waitProgress;
   int32 exitProgress;
 };
//GateStruc

//=======================  OS Thread related  ===============================

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


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

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

volatile MasterEnv      *_VMSMasterEnv __align_to_cacheline__;

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

//=========================  Function Prototypes  ===========================

/* MEANING OF   WL  PI  SS  int
 * These indicate which places the function is safe to use.  They stand for:
 * WL: Wrapper Library
 * PI: Plugin 
 * SS: Startup and Shutdown
 * int: internal to the VMS implementation
 */

//========== Setup and shutdown ==========
void
VMS_SS__init();

//Fix; 
/*seed-slaveVP creation -- put box around language, have lang register stuff
        with VMS.
        have main program explicitly INIT Lang! -- makes more sense to
        C programmers -- makes it clear that there's a transition.
(might need to have the pthreads remain waiting for
        cond until work is scheduled)
Have main do call to tell language to perform work -- like did with DKU

Ex: "HWSim__run_a_simulation(netlist, paramBag);"
        "processID = SSR__run_program(seed_fn, seedData); "
        "SSR__Wait_for_program_to_end(processID);"
        "SSR__run_program_and_wait_till_it_ends(seed_fn, seedData);"
        
        allows multiple languages to be started, and programs run in several,
        overlapped, or one program to be run that uses multiple langs..?
        So, each program is in separate directory:
            "HWSim_ArchDef__PingPong"  "SSR_Program__Blocked_Matrix_Mult"
        
        Those programs can talk to each other, via VMS, by handles they each
        return
        "processIDs[0] = SSR__run_program(seed_fn1, seedData1);"
        "processIDs[1] = SSR__run_program(seed_fn2, seedData2);"
        "SSR__link_programs(processIDs, 2);"
or even
        "processIDs[0] = Vthread__run_program(seed_fn1, seedData1);"
        "processIDs[1] = SSR__run_program(seed_fn2, seedData2);"
        "VMS__link_programs(processIDs, 2);"
        Then, the programs just know they sync with other prog, but use own
        lang's sync constructs -- VMS uses message system to establish tie-pt,
        each lang defines what a tie-point means to it..  (work with the
        diff semantics?)
*/
void
VMS_SS__start_the_work_then_wait_until_done();

void
VMS_SS__shutdown();

void
VMS_SS__cleanup_at_end_of_shutdown();


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

inline SlaveVP *
VMS_int__create_slaveVP( TopLevelFnPtr fnPtr, void *dataParam );
#define VMS_PI__create_slaveVP VMS_int__create_slaveVP
#define VMS_WL__create_slaveVP VMS_int__create_slaveVP

   //Use this to create processor inside entry point & other places outside
   // the VMS system boundary (IE, don't animate with a SlaveVP or MasterVP)
SlaveVP *
VMS_ext__create_slaveVP( TopLevelFnPtr fnPtr, void *dataParam );

inline SlaveVP *
VMS_int__create_slaveVP_helper( SlaveVP *newSlv,       TopLevelFnPtr  fnPtr,
                                void      *dataParam, void           *stackLocs );

inline void
VMS_int__point_slaveVP_to_Fn( SlaveVP *slaveVP, TopLevelFnPtr fnPtr,
                            void    *dataParam);

void
VMS_int__dissipate_slaveVP( SlaveVP *slaveToDissipate );
#define VMS_PI__dissipate_slaveVP VMS_int__dissipate_slaveVP
//WL: dissipate a SlaveVP by sending a request

void
VMS_ext__dissipate_slaveVP( SlaveVP *slaveToDissipate );

void
VMS_int__throw_exception( char *msgStr, SlaveVP *reqstSlv, VMSExcp *excpData );
#define VMS_PI__throw_exception VMS_int__throw_exception
#define VMS_WL__throw_exception VMS_int__throw_exception

void *
VMS_int__give_sem_env_for( SlaveVP *animSlv );
#define VMS_PI__give_sem_env_for  VMS_int__give_sem_env_for
#define VMS_SS__give_sem_env_for  VMS_int__give_sem_env_for
//No WL version -- not safe!  if use in WL, be sure data rd & wr is stable

//==============  Request Related  ===============

void
VMS_int__suspend_slaveVP_and_send_req( SlaveVP *callingSlv );

inline void
VMS_WL__add_sem_request_in_mallocd_VMSReqst( void *semReqData, SlaveVP *callingSlv );

inline void
VMS_WL__send_sem_request( void *semReqData, SlaveVP *callingSlv );

void
VMS_WL__send_create_slaveVP_req( void *semReqData, SlaveVP *reqstingSlv );

void inline
VMS_WL__send_dissipate_req( SlaveVP *prToDissipate );

inline void
VMS_WL__send_VMSSem_request( void *semReqData, SlaveVP *callingSlv );

VMSReqst *
VMS_PI__take_next_request_out_of( SlaveVP *slaveWithReq );

inline void *
VMS_PI__take_sem_reqst_from( VMSReqst *req );

void inline
VMS_PI__handle_VMSSemReq( VMSReqst *req, SlaveVP *requestingSlv, void *semEnv,
                       ResumeSlvFnPtr resumeSlvFnPtr );

//======================== MEASUREMENT ======================
uint64
VMS_WL__give_num_plugin_cycles();
uint32
VMS_WL__give_num_plugin_animations();


//========================= Utilities =======================
inline char *
VMS_int__strDup( char *str );


//========================= Probes =======================
#include "Probes/probes.h"

//================================================
#endif	/* _VMS_H */

