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

#ifndef _VSs_H
#define	_VSs_H

#include "Queue_impl/PrivateQueue.h"
#include "Hash_impl/PrivateHash.h"
#include "PR_impl/PR.h"
#include "Measurement/dependency.h"


//===========================================================================
   //uniquely identifies VSs -- should be a jenkins char-hash of "VSs" to int32
#define VSs_MAGIC_NUMBER 0000000001

#define NUM_STRUCS_IN_LANG_ENV 1000

   //This is hardware dependent -- it's the number of cycles of scheduling
   // overhead -- if a work unit is fewer than this, it is better being
   // combined sequentially with other work
   //This value depends on both PR overhead and VSs's plugin.  At some point
   // it will be derived by perf-counter measurements during init of VSs
#define MIN_WORK_UNIT_CYCLES 20000

//===========================================================================
/*This header defines everything specific to the VSs semantic plug-in
 */
typedef struct _VSsLangReq    VSsLangReq;
typedef struct _VSsTaskStub  VSsTaskStub;
typedef void  (*VSsTaskFnPtr )   ( void *, SlaveVP *);
typedef void  (*PtrToAtomicFn )  ( void * ); //executed atomically in master
//===========================================================================

#define NONCTLD 0
#define IN      1  /*Trick -- READER same as IN*/
#define OUT     2  /*Trick -- WRITER same as OUT and INOUT*/
#define INOUT   2  /*Trick -- WRITER same as OUT and INOUT*/

#define READER  1  /*Trick -- READER same as IN*/
#define WRITER  2  /*Trick -- WRITER same as OUT and INOUT*/

#define IS_A_THREAD NULL
#define IS_ENDED    NULL
#define SEED_SLV    NULL

#define NO_ID       NULL
#define ANY_CORE    -1

//===========================================================================
typedef struct
 {
   VSsTaskFnPtr fn;
   int32  numTotalArgs;//the number of inputs to function
   int32  numCtldArgs;//how many of args have dependencies
   int32 *argTypes;   //says reader, writer, or non-ctld
   int32 *argSizes;   //for detecting overlap
   int32  sizeOfArgs; //for memcpy of args struct
 }
VSsTaskType;


typedef struct
 {
   bool32       hasEnabledNonFinishedWriter;
   int32        numEnabledNonDoneReaders;
   PrivQueueStruc *waitersQ;
 }
VSsPointerEntry;

/*This is placed into langData, used for dependencies and wait construct*/
struct _VSsTaskStub
 {
 //====== The first fields must match PRLangMetaTask fields ======
   int32             langMagicNumber; //magic num must be 1st field of langMetaTask
   PRMetaTask       *protoMetaTask;   //back-link must always be 2nd field
 //====== end PRLangMetaTask fields =========
   void            **args;            //ctld args must be the first ones (as ptrs)
   VSsPointerEntry **ptrEntries;
   int32             numBlockingProp;
   
   VSsTaskType *taskType; //has VSs lang related info
   
   VSsTaskStub *parentTaskStub; //for liveness, for the wait construct
   int32        numLiveChildTasks;
   int32        numLiveChildThreads;
   bool32       isWaitingForChildTasksToEnd;
   bool32       isWaitingForChildThreadsToEnd;
   bool32       isEnded;
 };


typedef struct
 {
   VSsTaskStub *taskStub;
   int32        argNum;
   int32        isReader;
 }
VSsTaskStubCarrier;


/*Semantic layer-specific data sent inside a request from lib called in app
 * to request handler called in AnimationMaster
 */

typedef struct
 {
   SlaveVP      *VPCurrentlyExecuting;
   PrivQueueStruc *waitingVPQ;
 }
VSsTrans;

/*WARNING: assembly hard-codes position of endInstrAddr as first field
 */
typedef struct
 {
   void           *endInstrAddr;
   int32           hasBeenStarted;
   int32           hasFinished;
   PrivQueueStruc *waitQ;
 }
VSsSingleton;

enum VSsReqType
 {
   submit_task = 1,
   end_task,
   create_slave,
   create_slave_w_aff,
   dissipate_slave,
   //===============================
   send_type_to,
   receive_type_to,
   send_from_to,
   receive_from_to,
   //===============================
   taskwait,
   malloc_req,
   free_req,
   singleton_fn_start,
   singleton_fn_end,
   singleton_data_start,
   singleton_data_end,
   atomic,
   trans_start,
   trans_end
 };

struct _VSsLangReq
 { enum VSsReqType    reqType;
   SlaveVP           *callingSlv;
   VSsTaskType       *taskType;
   void              *args;
//   VSsTaskStub       *taskStub;  //not needed -- get via PR accessor from slv
   
   SlaveVP           *senderSlv;
   SlaveVP           *receiverSlv;
   int32             *senderID;
   int32             *receiverID;
   int32              msgType;
   void              *msg;
   VSsLangReq         *nextReqInHashEntry;
//In PRReq:   int32             *taskID;
   
   TopLevelFnPtr      fnPtr;
   void              *initData;
   int32              coreToAssignOnto;

//These, below, should move to util language..
   int32              sizeToMalloc;
   void              *ptrToFree;

   int32              singletonID;
   VSsSingleton     **singletonPtrAddr;

   PtrToAtomicFn      fnToExecInMaster;
   void              *dataForFn;

   int32              transID;
 }
/* VSsLangReq */;


typedef struct
 { 
   PrivQueueStruc  *slavesReadyToResumeQ; //Shared (slaves not pinned)
   PrivQueueStruc  *taskReadyQ;           //Shared (tasks not pinned)
   
   HashTable       *argPtrHashTbl;
   HashTable       *commHashTbl;
   int32            nextCoreToGetNewSlv;
   int32            primitiveStartTime;

                       //fix limit on num with dynArray
   VSsSingleton     fnSingletons[NUM_STRUCS_IN_LANG_ENV];
   VSsTrans         transactionStrucs[NUM_STRUCS_IN_LANG_ENV];
   
   #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   ListOfArrays* unitList;
   ListOfArrays* ctlDependenciesList;
   ListOfArrays* commDependenciesList;
   NtoN** ntonGroups;
   PrivDynArrayInfo* ntonGroupsInfo;
   ListOfArrays* dynDependenciesList;
   Unit last_in_slot[NUM_CORES * NUM_ANIM_SLOTS];
   ListOfArrays* hwArcs;
   #endif

   #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS
   ListOfArrays* counterList[NUM_CORES];
   #endif
 }
VSsLangEnv;


typedef struct _TransListElem TransListElem;
struct _TransListElem
 {
   int32          transID;
   TransListElem *nextTrans;
 };
//TransListElem
 
/* PR now handles what this used to be used for
enum VSsSlvType
 { FreeTaskSlv = 1,
   SlotTaskSlv,
   ThreadSlv
 };
*/
 
typedef struct
 {
   int32            highestTransEntered;
   TransListElem   *lastTransEntered;
   int32            primitiveStartTime;
//   VSsTaskStub     *taskStub; //get from slave via PR accessor
 }
VSsLangData;
 
//===========================================================================

void
VSs__create_seed_slave_and_do_work( TopLevelFnPtr fn, void *initData );

int32
VSs__giveMinWorkUnitCycles( float32 percentOverhead );

void
VSs__begin_primitive();

int32
VSs__end_primitive_and_give_cycles();

int32
VSs__giveIdealNumWorkUnits();

int32
VSs__give_number_of_cores_to_schedule_onto();

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

void
VSs__start( SlaveVP *seedSlv );

void
VSs__cleanup_after_shutdown();

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

SlaveVP *
VSs__create_thread( TopLevelFnPtr fnPtr,   void *initData,
                                                     SlaveVP *creatingThd );

void
VSs__end_thread( SlaveVP *thdToEnd );

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

#define VSs__malloc( numBytes, callingSlave ) PR_App__malloc( numBytes, callingSlave)

#define VSs__free(ptrToFree, callingSlave ) PR_App__free( ptrToFree, callingSlave )


//=======================
void
VSs__submit_task( VSsTaskType *taskType, void *args, SlaveVP *animSlv);

inline int32 *
VSs__create_taskID_of_size( int32 numInts, SlaveVP *animSlv );

void
VSs__submit_task_with_ID( VSsTaskType *taskType, void *args, int32 *taskID, 
                          SlaveVP     *animSlv);

void
VSs__end_task( SlaveVP *animSlv );

//=========================
void
VSs__taskwait(SlaveVP *animSlv);


inline int32 *
VSs__give_self_taskID( SlaveVP *animSlv );

void
VSs__send_of_type_to( void *msg, const int32 type, int32 *receiverID,
                      SlaveVP *senderSlv );

void
VSs__send_from_to( void *msg, int32 *senderID, int32 *receiverID, SlaveVP *senderSlv );

void *
VSs__receive_type_to( const int32 type, int32* receiverID, SlaveVP *receiverSlv );

void *
VSs__receive_from_to( int32 *senderID, int32 *receiverID, SlaveVP *receiverSlv );

//======================= Concurrency Stuff ======================
void
VSs__start_fn_singleton( int32 singletonID, SlaveVP *animSlv );

void
VSs__end_fn_singleton( int32 singletonID, SlaveVP *animSlv );

void
VSs__start_data_singleton( VSsSingleton **singeltonAddr, SlaveVP *animSlv );

void
VSs__end_data_singleton( VSsSingleton **singletonAddr, SlaveVP *animSlv );

void
VSs__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster,
                                    void *data, SlaveVP *animSlv );

void
VSs__start_transaction( int32 transactionID, SlaveVP *animSlv );

void
VSs__end_transaction( int32 transactionID, SlaveVP *animSlv );


//=========================  Internal use only  =============================
void
VSs__Request_Handler( SlaveVP *requestingSlv, void *_langEnv );

SlaveVP *
VSs__assign_work_to_slot( void *_langEnv, AnimSlot *slot );

SlaveVP*
VSs__create_slave_helper( TopLevelFnPtr fnPtr, void *initData,
                          VSsLangEnv *langEnv,    int32 coreToAssignOnto );

SlaveVP *
VSs__create_slave_with( TopLevelFnPtr fnPtr, void *initData,
                          SlaveVP *creatingSlv );

SlaveVP *
VSs__create_slave_with_affinity( TopLevelFnPtr fnPtr,    void *initData,
                            SlaveVP *creatingSlv, int32 coreToAssignOnto);

//=====================    =====================
inline 
void *
handleSubmitTask( VSsLangReq *langReq, VSsLangEnv *langEnv );
inline 
void
handleEndTask( VSsLangReq *langReq, SlaveVP *requestingSlv, VSsLangEnv *langEnv );


//=====================  Measurement of Lang Overheads  =====================
#include "Measurement/VSs_Measurement.h"

//===========================================================================
#endif	/* _VSs_H */

