/*
 *  Copyright 2009 OpenSourceStewardshipFoundation.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 "VMS_impl/VMS.h"
#include "Measurement/dependency.h"


//===========================================================================
#define NUM_STRUCS_IN_SEM_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 VMS 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 _VSsSemReq   VSsSemReq;
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

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;

typedef struct
 {
   void       **args; //ctld args must come first, as ptrs
   VSsTaskType *taskType;
   int32       *taskID;
   int32        numBlockingProp;
   SlaveVP     *slaveAssignedTo; //only valid before end task (thread)
   VSsPointerEntry  **ptrEntries;
   void*        parentTaskStub;
   int32        numLiveChildTasks;
   int32        numLiveChildThreads;
   bool32       isWaitingForChildTasksToEnd;
   bool32       isWaitingForChildThreadsToEnd;
   bool32       isEnded;
 }
VSsTaskStub;


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 _VSsSemReq
 { enum VSsReqType    reqType;
   SlaveVP           *callingSlv;
   VSsTaskType       *taskType;
   void              *args;
   VSsTaskStub       *taskStub;
   
   SlaveVP           *senderSlv;
   SlaveVP           *receiverSlv;
   int32             *senderID;
   int32             *receiverID;
   int32              msgType;
   void              *msg;
   VSsSemReq         *nextReqInHashEntry;
   int32             *taskID;
   
   TopLevelFnPtr      fnPtr;
   void              *initData;
   int32              coreToAssignOnto;

   int32              sizeToMalloc;
   void              *ptrToFree;

   int32              singletonID;
   VSsSingleton     **singletonPtrAddr;

   PtrToAtomicFn      fnToExecInMaster;
   void              *dataForFn;

   int32              transID;
 }
/* VSsSemReq */;


typedef struct
 {
   PrivQueueStruc  *slavesReadyToResumeQ; //Shared (slaves not pinned)
   PrivQueueStruc  *freeExtraTaskSlvQ;    //Shared
   PrivQueueStruc  *taskReadyQ;           //Shared (tasks not pinned)
   SlaveVP         *slotTaskSlvs[NUM_CORES][NUM_ANIM_SLOTS];
   HashTable       *argPtrHashTbl;
   HashTable       *commHashTbl;
   int32            numLiveExtraTaskSlvs;
   int32            numLiveThreadSlvs;
   int32            nextCoreToGetNewSlv;
   int32            primitiveStartTime;

                       //fix limit on num with dynArray
   VSsSingleton     fnSingletons[NUM_STRUCS_IN_SEM_ENV];
   VSsTrans         transactionStrucs[NUM_STRUCS_IN_SEM_ENV];

   bool32          *coreIsDone;
   int32            numCoresDone;
   
   #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
   SlaveVP* idleSlv[NUM_CORES][NUM_ANIM_SLOTS];
   int shutdownInitiated;
 }
VSsSemEnv;


typedef struct _TransListElem TransListElem;
struct _TransListElem
 {
   int32          transID;
   TransListElem *nextTrans;
 };
//TransListElem
 
enum VSsSlvType
 { ExtraTaskSlv = 1,
   SlotTaskSlv,
   ThreadSlv
 };
 
typedef struct
 {
   int32           highestTransEntered;
   TransListElem  *lastTransEntered;
   bool32          needsTaskAssigned;
   VSsTaskStub    *taskStub;
   enum VSsSlvType slaveType;
 }
VSsSemData;
 
//===========================================================================

void
VSs__create_seed_slave_and_do_work( TopLevelFnPtr fn, void *initData );

int32
VSs__giveMinWorkUnitCycles( float32 percentOverhead );

void
VSs__start_primitive();

int32
VSs__end_primitive_and_give_cycles();

int32
VSs__giveIdealNumWorkUnits();

int32
VSs__give_number_of_cores_to_schedule_onto();

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

void
VSs__init();

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 ) VMS_App__malloc( numBytes, callingSlave)

#define VSs__free(ptrToFree, callingSlave ) VMS_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 *_semEnv );

SlaveVP *
VSs__assign_slaveVP_to_slot( void *_semEnv, AnimSlot *slot );

SlaveVP*
VSs__create_slave_helper( TopLevelFnPtr fnPtr, void *initData,
                          VSsSemEnv *semEnv,    int32 coreToAssignOnto );

VSsTaskStub *
create_thread_task_stub( void *initData );


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);

void 
idle_fn(void* data, SlaveVP *animatingSlv);

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

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

