/*
 * User-level thread library
 *
 * Author: os@cs.huji.ac.il, HUJI OS fall 2002
 * 
 * 
 *
 */

#define USECOND 1    /* microsecond */
#define SECOND USECOND*1000000 /* microseconds in second */
#define V_QUANTUM 10; /* virtual time quantum in simulated clock ticks; NOTE NEW ITEM! */


struct thread_status {
  long total_time;  /* total time spent by this thread from the moment it was
                       spawned to the moment it performed uthreads_exit() (in 
                       microseconds) */
  long run_time; /* total time that this thread spent running (in microseconds) */  
  long bursts;   /* number of times this thread has been scheduled to run */
  long v_ticks; /* number of simulated clock ticks; NOTE NEW ITEM! */
};

/*
 * uthreads_init() initializes the data structures internal to the library.
 * Arguments: none
 * Return value: -1 in case of a failure
 * Reasons for failure: the library was already initiated, not enough memory to allocate
 *                      the data structures for the library.
 */

int uthreads_init(void); /* call this once before launching any threads */


/*
 * uthreads_spawn() function is called to create a stack within the library. 
 * This function only creates the thread, but does not execute it. The thread starts
 * executing only when uthreads_start() function is called, and it is either the first thread
 * in the ready list, or some other thread has yielded the CPU.
 *
 * Arguments: 
 *     - size of the stack for this thread: should be positive
 *     - pointer on the function that should be
 *       executed within this thread: should be non-null
 *     - argument of the function.
 *
 * Return values: -1 in case of failure, valid thread id 
 * (running long integer value starting from 0) in case of success.
 *
 * Reasons for failure: premature call, insufficient memory, invalid function pointer etc. 
 */ 

long uthreads_spawn(int stacksize, void (* proc)(int), int param); /* call this to create proc(param) as a thread */
                                                                  /* may be called from main or from any thread */


/* 
 * uthreads_start() function starts execution of the threads. 
 * This function is called after at least one thread has been created through 
 * function uthreads_spawn(). It does not return until the last thread from the 
 * thread set terminates. This function may be called more than once throughout the
 * program, but only once per each thread set.
 *
 * Arguments: none
 * Return value: -1 in case of failure
 * Reasons for failure: 
 *   - the function is called more than once for the current thread set,
 *     e.g., a thread from the current set calls this function;
 *   - premature call: the function is called when no threads were previously created via
 *     uthreads_spawn();
 *   - could not transfer control for the first time for some reason
 *
 */

int uthreads_start(void); /* call this once after launching at least one thread */
                          /* this function returns only when all threads finish! */
                          /* the intended usage is to call it from the main() function */ 

/*
 * uthreads_yield() function is called from within a thread that currently runs,
 * to relinquish CPU to another thread. This is a central function to any non-preemptible 
 * scheduling mechanism. In case there is no other thread in a system at the moment, the 
 * calling thread (the one that executes at the moment) should retain control of the CPU.
 *
 * Arguments: none
 * Return value: -1 in case of failure
 * Reasons for failure: 
 *    - premature call: e.g., called from main 
 *    - could not perform context switch for some reason
 */

int uthreads_yield(); /* call from within a thread to allow scheduling of a new thread */

/*
 * uthreads_exit() function is called from within the currently running thread in order to
 * terminate this thread. Terminated thread enters the special ZOMBY state. In this state
 * thread does not participate in scheduling, but retains information (statistics) about its
 * execution. This information can be obtained through uthreads_wait() function.
 *
 * Note 1: when last thread from the current thread set terminates, the function 
 * uthreads_start() returns.
 *
 * Note 2: may fail if called in an inappropriate location. Does not return value, but sets up
 *         error condition in the library so that uthreads_perror() prints error message 
 *         correctly.
 *
 * Arguments: none 
 * Return values: none. Note that in case of success this function has no place to return.
 */

void uthreads_exit(); /* call from within a thread to terminate the caller */

/*
 * uthreads_wait() is similar to wait(), but note the following important differences.
 * 1) uthreads_wait() is non-blocking:
 *     - in case there is no thread being in the ZOMBY state, uthread_wait() returns with -1 
 *     - in case there are one or more threads in ZOMBY state, uthread_wait() returns with
 *       the thread id (TID) of some finished thread being a long integer, 
 *       and fills the statistics structure, if the function's argument is non-NULL pointer
 * 2) any thread can call uthreads_wait(). In contrast to Unix wait(), the father-child 
 *    relationships play no role     
 *
 * Note: we never know which thread will be cleared from the ZOMBY state by uthreads_wait() 
 *
 * Arguments: struct thread_status*, which points to a structure that should hold statistics.
 *            If NULL pointer is specified, uthreads_wait() does everything, but fills the 
 *            statistics structure.
 * 
 * Return values: -1 in case of failure, long integer being a valid TID otherwise
 * Reasons for failure: 
 *   - premature function call (e.g., no threads at all; called prior to initialization etc.) 
 *   - no threads in ZOMBY state
 */

long uthreads_wait(struct thread_status*); /* call to find out statistics about a thread,
                                              and to remove it permanently from the library 
                                              data structures */


/*
 *
 * This function is called by the uthreads library user in order to find out what
 * was the reason for the last failed call to the uthreads library function (i.e., the
 * last call that returned with -1). After uthreads_perror() is called, the error 
 * condition is cleared. Similarly to perror(), this function prints out the predefine
 * message (i.e., the message defined inside your library) + user's message passed as an 
 * argument. 
 *
 * Arguments: user message, similarly to perror()
 * Return values: none
 */

void uthreads_perror(char*);

/*
 * This function is called to create a new semaphore whose value is initialized
 * to the value of the argument. 
 *
 *  Argument: initial value of the semaphore; integer value.
 *  Return values: in case of success returns non-negative integer that represents the 
 *  semaphore ID (semid). The semid is used as an argument to the semaphore related functions.
 *  In case of any error, should return -1.
 *
 *  Note that the correctness of the initial value is a responsibility of the user.
 */

int uthreads_semcreate(int value);

/*
 * This function is called on a valid semid. This is a usual wait() operation on a semaphore
 * See exercise definition for details.
 *
 * Arguments: valid semid.
 * Return values: If a user specifies an invalid semid, the function should return -1. 
 * Otherwise, if the operation can be completed without blocking, the function returns 
 * immediately with 0.
 */

int uthreads_semwait(int semid);


/*
 * This function is called on a valid semid. This is a usual signal() operation on a semaphore
 * See exercise definition for details.
 *
 * Arguments: valid semid.
 * Return values: If a user specifies an invalid semid, the function should return -1. 
 * Otherwise, if the operation can be completed without blocking, the function returns 
 * immediately with 0.
 */

int uthreads_semsignal(int semid);


/*
 * This function is called on the valid thread id (TID) to suspend the execution of the 
 * thread with this TID. See exercise definition for details.
 *
 * Arguments: valid TID.
 * Return values: -1 if TID refers to a non-existed, non-started, already suspended, or
 * already terminated thread. Note that when semwait() blocks the calling thread is already
 * suspended. In case of success, returns with the TID of the suspended thread.
 *
 */

long uthreads_suspend(long tid);

/*
 * This function is the opposite of uthreads_suspend(). See exercise definition for details.
 *
 * Arguments: valid TID.
 * Return values: -1 if applied to a non-existent, terminated, non-suspended thread, and TID
 * of the resumed thread otherwise.
 */

long uthreads_resume(long tid);

/*
 * Auxiliary function that gives information about the threads in the library.
 * Can becalled at any time, but only after the library is initilized.
 * this function fills the buffer of the specified size pointed to by buf with 
 * the status information about the threads in the library. If 
 * the buffer is not large enough, then this function fails, and returns with -1. Otherwise it
 * fills the buffer with the lines in the following format:
 * TID SchedulingState TotalTime RunTime Bursts V-TICKS
 * The list should be sorted by the TID number. 
 * The last character in the buffer should be '\0'. Please, note this, 
 * and don't forget to add terminate the buffer \
 * properly.                                                
 * 
 * Arguments: pointer to the character buffer, size of the buffer
 * Return values: -1 in case of failure, 0 in case of success.
 */

int uthreads_ps(char* buf, int size);





















