#include #include #include #include #include //Mutex types #define PTHREAD_MUTEX_DEFAULT 0 #define PTHREAD_MUTEX_NORMAL 0 #define PTHREAD_MUTEX_RECURSIVE 1 #define PTHREAD_MUTEX_ERRORCHECK 2 //Attribute Constants #define PTHREAD_CREATE_DETACHED 0 #define PTHREAD_CREATE_JOINABLE 1 //Mutex initializer #define PTHREAD_MUTEX_INITIALIZER \ {0,0,0,PTHREAD_MUTEX_NORMAL,__LOCK_INITIALIZER} #define __LOCK_INITIALIZER { 0, 0 } #define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER,0} typedef struct { void *stackaddr; size_t stacksize; size_t guardsize; int detachstate; int inheritsched; int contentionscope; int policy; } pthread_attr_t; /* pthread_t struct definition Contains a $proc and a pthread_attr_t which describes how it interacts with other threads and certain methods */ typedef struct { $proc thr; const pthread_attr_t *attr; } pthread_t; /* pthread_mutex_t struct definition Fields: count - used for recursive mutex, incremented when locked, decremented when unlocked, mutex released when count is 0 owner - current process owner of the mutex lock - int of 0 or 1, respectively 0 if unlocked, 1 if locked kind - type of mutex, types defined at beginning of this file */ typedef struct { int count; $proc owner; int lock; int kind; } pthread_mutex_t; /* pthread_attr_t struct definition */ /* pthread_mutexattr_t struct definition Fields: robust: defines the robustness of the mutex typedef struct { int robust; int pshared; int protocol; int type; int prioceiling; }pthread_mutexattr_t; */ /* typedef struct { int pshared; clockid_t clock_id; }pthread_condattr_t; */ /* pthread_cond_t struct definition Fields: procount - specifies the number of processes/threads still waiting on this condition variable signal - Boolean value stating whether the condition is satisfied (indicated by 1) or not (0) */ typedef struct { int proccount; _Bool signal; } pthread_cond_t; int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg){ thread->thr = $spawn start_routine(arg); thread->attr = attr; return 0; } /* Causes current thread to wait on thread specified as a paremeter. If specified thread's detachstate field is set as PTHREAD_CREATE_DETACHED, error will be returned stating the the thread cannot be joined. */ int pthread_join(pthread_t thread, void **value_ptr) { if(thread.attr->detachstate == 0){ $assert($false, "Thread is designated as unjoinable"); return 1; } $wait(thread.thr); return 0; } /* Calls CIVL $exit method causing the current thread to immediately terminate */ int pthread_exit(void *arg){ $exit(); return 0; } int pthread_detach(pthread_t thread); /* Initializes the condition variable so that it begins with 0 processes waiting on it as well as a signal set to be zero **Needs to be modified to work with condition attributes as the second parameter */ void pthread_cond_init(pthread_cond_t *cond, void *arg){ cond->proccount = 0; cond->signal = 0; } /* Unitializes the condition parameter and then frees the data used to store it. If certains threads are still waiting when pthread_cond_destroy is called, an error will be triggered. */ void pthread_cond_destroy(pthread_cond_t *cond){ if(cond->proccount != 0){ $assert($false, "ERROR: Threads still waiting on specified condition variable"); } else{ pthread_cond_t blank; *cond = blank; } } //Initializes mutex as unlocked and kind as defined by int m void pthread_mutex_init(pthread_mutex_t *mutex, int m){ mutex->kind = m; mutex->lock = 0; mutex->count = 0; mutex->owner = $proc_null; } void pthread_mutex_destroy(pthread_mutex_t *mutex){ pthread_mutex_t blank; *mutex = blank; } /* pthread_mutex_lock takes in a mutex variable and acts accordingly to its current state and type PTHREAD_MUTEX_NORMAL: Checks to see whether mutex is already locked and behaves accordingly locked and owner: Relock error, returns 0 locked and not owner: Waits until mutex is unlocked and then locks and becomes owner unlocked and not owner: Locks the mutex and becomes owner PTHREAD_MUTEX_RECURSIVE */ int pthread_mutex_lock(pthread_mutex_t *mutex) { $atomic{ if (mutex->kind == PTHREAD_MUTEX_NORMAL){ if (mutex->lock != 0) { if(mutex->owner == $proc_null){ $when(mutex->lock == 0); } else{ if(mutex->owner == $self){ $assert($false, "ERROR: Relock attempted"); return 0; } else{ $when(mutex->lock == 0); } } } mutex->owner = $self; mutex->lock = 1; } else { int tmp = mutex->lock; mutex->lock = 1; if (tmp == 0) { // Attempts lock and checks for whether lock is already locked mutex->count = 1; mutex->owner = $self; } else { //Checks for ownership, otherwise returns error if(mutex->owner == $self) { // Checks for recursive mutex, otherwise returns an error if (mutex->kind == 1) { mutex->count++; if(mutex->count==0){ mutex->lock = 0; mutex->owner = $proc_null; } } else { $assert($false); return 0; } } else { $assert($false); return 0; } } } return 0; } } int pthread_mutex_unlock(pthread_mutex_t *mutex) { $atomic{ if (mutex->kind == 0 || mutex->kind == 2) { int idx; // Attempts unlock, if already unlocked, returns error if (mutex->lock == 0) { $assert($false, "Attempting to unlock unlocked lock\n"); return 0; } else { mutex->lock = 0; mutex->owner = $proc_null; } } else { //Checks for ownership of thread, if not, returns error if(mutex->owner == $self) { //Checks for recursive mutex _Bool tmp = !(mutex->kind == 1); if (--mutex->count == 0){ mutex->lock = 0; mutex->owner = $proc_null; } } else { $assert($false); return 0; } } return 0; } } int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex){ if(mutex->owner != $self) { printf("Mutex not owned by thread"); $assert($false); return 0; } cond->proccount= cond->proccount+1; pthread_mutex_unlock(mutex); $when(cond->signal); cond->signal = 0; --cond->proccount; $when(mutex->lock == 0){pthread_mutex_lock(mutex);} return 0; } int pthread_cond_signal(pthread_cond_t *cond){ cond->signal = 1; return 0; } int pthread_cond_broadcast(pthread_cond_t *cond){ while(cond->proccount > 0){ cond->signal = 1; } return 0; } int pthread_attr_init(pthread_attr_t *attr){ attr->stacksize = 0; attr->guardsize = 0; attr->detachstate = PTHREAD_CREATE_DETACHED; //attr->inheritsched = PTHREAD_EXPLICIT_SCHED; //attr->scope = PTHREAD_SCOPE_SYSTEM; attr->stackaddr = NULL; //attr->policy = SCHED_OTHER; return 0; } //Destroy thread attribute int pthread_attr_destroy(pthread_attr_t *attr) { pthread_attr_t *tmp = attr; pthread_attr_t blank; *attr = blank; $free(tmp); } //Set the detachstate attribute int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) { attr->detachstate = detachstate; return 0; } //Return the detachstate attribute int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) { *detachstate = attr->detachstate; return 0; } //Set scheduling inheritance int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched) { attr->inheritsched = inheritsched; return 0; } //Return the scheduling inheritance int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched) { *inheritsched = attr->inheritsched; return 0; } /*Set scheduling contention scope int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope) { attr->scope = contentionscope; return 0; } //Return the scheduling contention scope int pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope) { *contentionscope = attr->scope; return 0; } */ //Set the starting address of the stack of the thread int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) { attr->stackaddr = stackaddr; return 0; } //Return the address for the stack int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) { *stackaddr = attr->stackaddr; return 0; } //Set stack size int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) { attr->stacksize = stacksize; return 0; } //Return the stack size int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) { *stacksize = attr->stacksize; return 0; } //Set guard size int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) { attr->guardsize = guardsize; return 0; } // Return guard size int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize) { *guardsize = attr->guardsize; return 0; } //Set scheduling policy int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) { attr->policy = policy; return 0; } // Return scheduling policy int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) { *policy = attr->policy; return 0; }