/*
 *  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"

extern void free_pointer_entry(void* ptrEntry);
/* Switch for Nexus support
 * Note: nexus incompatible with holistic recording (constraints not accessible)
 * But counter recording still functional, can build constraintless display
 * with wallclock time
 */
//#define EXTERNAL_SCHEDULER
//#define SIMULATE_EXTERNAL_SCHEDULER

//===========================================================================
#define NUM_STRUCS_IN_SEM_ENV 1000

#define MAX_TASKS_NUM 5

   //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 * );
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  numDeps;//how many of args have dependencies
   int32 *depsTypes;   //says reader, writer, or non-ctld
   size_t *depsSizes;   //for detecting overlap
   int32  sizeOfArgs; //for memcpy of args struct
 }
VSsTaskType;


typedef struct
 {
   bool32       hasEnabledNonFinishedWriter;
   int32        numEnabledNonDoneReaders;
   PrivQueueStruc *waitersQ;
#ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   Unit lastWriter;
   ListOfArrays* readersSinceLastWriter;
#endif
 }
VSsPointerEntry;

typedef struct {
    void **args; //for calling only, can contain values
    void** depsAddrs; //pointers only 
    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;
    int *depsMask;
#ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
    Unit parentUnit;
    Unit firstOfTask;
#endif
}
VSsTaskStub;


typedef struct
 {
   VSsTaskStub *taskStub;
   int32        argNum;
   int32        isReader;
   bool32       isSuspended;
 }
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;
#ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   Unit executingUnit;
#endif
 }
VSsSingleton;

typedef struct
 {
   int32           isOccupied;
   PrivQueueStruc *waitQ;
#ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   Unit            previous;
#endif
 }
VSsCritical;

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,
   taskwait_on,
   critical_start,
   critical_end,
   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;
   void              *deps;
   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;
   void*              criticalID;
 }
/* 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;
   HashTable       *criticalHashTbl;
   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;
   
   int              numInFlightTasks;
   PrivQueueStruc  *deferredSubmitsQ;
   int              numDeferred;
   
   #ifdef HOLISTIC__TURN_ON_OBSERVE_UCC
   ListOfArrays* unitList;
   ListOfArrays* ctlDependenciesList;
   ListOfArrays* commDependenciesList;
   ListOfArrays* dataDependenciesList;
   ListOfArrays* warDependenciesList;
   NtoN** ntonGroups;
   PrivDynArrayInfo* ntonGroupsInfo;
   ListOfArrays* dynDependenciesList;
   ListOfArrays* singletonDependenciesList;
   Unit last_in_slot[NUM_CORES * NUM_ANIM_SLOTS];
   ListOfArrays* hwArcs;
   #endif

   #ifdef HOLISTIC__TURN_ON_PERF_COUNTERS
   ListOfArrays* counterList[NUM_CORES];
   #endif
   #ifdef IDLE_SLAVES
   SlaveVP* idleSlv[NUM_CORES][NUM_ANIM_SLOTS];
   #endif
   //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__run_thread(TopLevelFnPtr fnPtr, void *initData);

void
VSs__end_thread();

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

#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, void* deps);

int32 *
VSs__create_taskID_of_size( int32 numInts);

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

void VSs__run_task(TopLevelFnPtr fnPtr, void *initData);

void
VSs__end_task();

//=========================
void
VSs__taskwait();

void
VSs__taskwait_on(void* ptr);

void
VSs__start_critical(void* name);

void
VSs__end_critical(void* name);

int32 *
VSs__give_self_taskID();

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

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

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

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

//======================= Concurrency Stuff ======================
void
VSs__start_fn_singleton( int32 singletonID );

void
VSs__end_fn_singleton( int32 singletonID );

void
VSs__start_data_singleton( VSsSingleton **singeltonAddr );

void
VSs__end_data_singleton( VSsSingleton **singletonAddr );

void
VSs__animate_short_fn_in_isolation( PtrToAtomicFn ptrToFnToExecInMaster,
                                    void *data );

void
VSs__start_transaction( int32 transactionID );

void
VSs__end_transaction( int32 transactionID );


//=========================  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(TopLevelFnWrapper fnWrapper, 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);

void
resume_slaveVP(SlaveVP *slave, VSsSemEnv *semEnv);

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

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

/* Hide entry point trick */

typedef struct {
    int argc;
    char** argv;
} __main_args;

extern int __main_ret;

int __program_main(int argc, char** argv);

void __entry_point(void* _args);

int main(int argc, char** argv);


#define main __program_main

#endif	/* _VSs_H */

