| 1 | #include <civlc.h>
|
|---|
| 2 | #include <stdio.h>
|
|---|
| 3 | #include <stdlib.h>
|
|---|
| 4 | #include <assert.h>
|
|---|
| 5 | #include <stdbool.h>
|
|---|
| 6 |
|
|---|
| 7 | //Mutex types
|
|---|
| 8 | #define PTHREAD_MUTEX_DEFAULT 0
|
|---|
| 9 | #define PTHREAD_MUTEX_NORMAL 0
|
|---|
| 10 | #define PTHREAD_MUTEX_RECURSIVE 1
|
|---|
| 11 | #define PTHREAD_MUTEX_ERRORCHECK 2
|
|---|
| 12 |
|
|---|
| 13 | //Attribute Constants
|
|---|
| 14 | #define PTHREAD_CREATE_DETACHED 0
|
|---|
| 15 | #define PTHREAD_CREATE_JOINABLE 1
|
|---|
| 16 |
|
|---|
| 17 |
|
|---|
| 18 | //Mutex initializer
|
|---|
| 19 | #define PTHREAD_MUTEX_INITIALIZER \
|
|---|
| 20 | {0,0,0,PTHREAD_MUTEX_NORMAL,__LOCK_INITIALIZER}
|
|---|
| 21 | #define __LOCK_INITIALIZER { 0, 0 }
|
|---|
| 22 | #define PTHREAD_COND_INITIALIZER {__LOCK_INITIALIZER,0}
|
|---|
| 23 |
|
|---|
| 24 | typedef struct {
|
|---|
| 25 | void *stackaddr;
|
|---|
| 26 | size_t stacksize;
|
|---|
| 27 | size_t guardsize;
|
|---|
| 28 | int detachstate;
|
|---|
| 29 | int inheritsched;
|
|---|
| 30 | int contentionscope;
|
|---|
| 31 | int policy;
|
|---|
| 32 | } pthread_attr_t;
|
|---|
| 33 |
|
|---|
| 34 | /* pthread_t struct definition
|
|---|
| 35 | Contains a $proc and a pthread_attr_t which describes how it interacts with other threads and certain methods
|
|---|
| 36 | */
|
|---|
| 37 | typedef struct {
|
|---|
| 38 | $proc thr;
|
|---|
| 39 | const pthread_attr_t *attr;
|
|---|
| 40 | } pthread_t;
|
|---|
| 41 |
|
|---|
| 42 | /* pthread_mutex_t struct definition
|
|---|
| 43 | Fields: count - used for recursive mutex, incremented when locked, decremented when unlocked, mutex released when count is 0
|
|---|
| 44 | owner - current process owner of the mutex
|
|---|
| 45 | lock - int of 0 or 1, respectively 0 if unlocked, 1 if locked
|
|---|
| 46 | kind - type of mutex, types defined at beginning of this file
|
|---|
| 47 | */
|
|---|
| 48 | typedef struct {
|
|---|
| 49 | int count;
|
|---|
| 50 | $proc owner;
|
|---|
| 51 | int lock;
|
|---|
| 52 | int kind;
|
|---|
| 53 | } pthread_mutex_t;
|
|---|
| 54 |
|
|---|
| 55 | /* pthread_attr_t struct definition
|
|---|
| 56 |
|
|---|
| 57 |
|
|---|
| 58 | */
|
|---|
| 59 |
|
|---|
| 60 |
|
|---|
| 61 | /* pthread_mutexattr_t struct definition
|
|---|
| 62 | Fields: robust: defines the robustness of the mutex
|
|---|
| 63 |
|
|---|
| 64 |
|
|---|
| 65 |
|
|---|
| 66 | typedef struct {
|
|---|
| 67 | int robust;
|
|---|
| 68 | int pshared;
|
|---|
| 69 | int protocol;
|
|---|
| 70 | int type;
|
|---|
| 71 | int prioceiling;
|
|---|
| 72 | }pthread_mutexattr_t;
|
|---|
| 73 | */
|
|---|
| 74 | /*
|
|---|
| 75 | typedef struct {
|
|---|
| 76 | int pshared;
|
|---|
| 77 | clockid_t clock_id;
|
|---|
| 78 | }pthread_condattr_t;
|
|---|
| 79 | */
|
|---|
| 80 |
|
|---|
| 81 | /* pthread_cond_t struct definition
|
|---|
| 82 | Fields: procount - specifies the number of processes/threads still waiting on this condition variable
|
|---|
| 83 | signal - Boolean value stating whether the condition is satisfied (indicated by 1) or not (0)
|
|---|
| 84 | */
|
|---|
| 85 | typedef struct {
|
|---|
| 86 | int proccount;
|
|---|
| 87 | _Bool signal;
|
|---|
| 88 | } pthread_cond_t;
|
|---|
| 89 |
|
|---|
| 90 | int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void*), void *arg){
|
|---|
| 91 | thread->thr = $spawn start_routine(arg);
|
|---|
| 92 | thread->attr = attr;
|
|---|
| 93 | return 0;
|
|---|
| 94 | }
|
|---|
| 95 |
|
|---|
| 96 | /* Causes current thread to wait on thread specified as a paremeter. If specified thread's detachstate field is set as PTHREAD_CREATE_DETACHED,
|
|---|
| 97 | error will be returned stating the the thread cannot be joined.
|
|---|
| 98 | */
|
|---|
| 99 | int pthread_join(pthread_t thread, void **value_ptr) {
|
|---|
| 100 | if(thread.attr->detachstate == 0){
|
|---|
| 101 | $assert($false, "Thread is designated as unjoinable");
|
|---|
| 102 | return 1;
|
|---|
| 103 | }
|
|---|
| 104 | $wait(thread.thr);
|
|---|
| 105 | return 0;
|
|---|
| 106 | }
|
|---|
| 107 |
|
|---|
| 108 | /* Calls CIVL $exit method causing the current thread to immediately terminate
|
|---|
| 109 |
|
|---|
| 110 | */
|
|---|
| 111 | int pthread_exit(void *arg){
|
|---|
| 112 | $exit();
|
|---|
| 113 | return 0;
|
|---|
| 114 | }
|
|---|
| 115 |
|
|---|
| 116 | int pthread_detach(pthread_t thread);
|
|---|
| 117 |
|
|---|
| 118 | /* Initializes the condition variable so that it begins with 0 processes waiting on it as well as a signal set to be zero
|
|---|
| 119 | **Needs to be modified to work with condition attributes as the second parameter
|
|---|
| 120 | */
|
|---|
| 121 | void pthread_cond_init(pthread_cond_t *cond, void *arg){
|
|---|
| 122 | cond->proccount = 0;
|
|---|
| 123 | cond->signal = 0;
|
|---|
| 124 | }
|
|---|
| 125 |
|
|---|
| 126 | /* Unitializes the condition parameter and then frees the data used to store it. If certains threads are still waiting when
|
|---|
| 127 | pthread_cond_destroy is called, an error will be triggered.
|
|---|
| 128 | */
|
|---|
| 129 | void pthread_cond_destroy(pthread_cond_t *cond){
|
|---|
| 130 | if(cond->proccount != 0){
|
|---|
| 131 | $assert($false, "ERROR: Threads still waiting on specified condition variable");
|
|---|
| 132 | }
|
|---|
| 133 | else{
|
|---|
| 134 | pthread_cond_t blank;
|
|---|
| 135 | *cond = blank;
|
|---|
| 136 | }
|
|---|
| 137 | }
|
|---|
| 138 |
|
|---|
| 139 | //Initializes mutex as unlocked and kind as defined by int m
|
|---|
| 140 | void pthread_mutex_init(pthread_mutex_t *mutex, int m){
|
|---|
| 141 | mutex->kind = m;
|
|---|
| 142 | mutex->lock = 0;
|
|---|
| 143 | mutex->count = 0;
|
|---|
| 144 | mutex->owner = $proc_null;
|
|---|
| 145 | }
|
|---|
| 146 |
|
|---|
| 147 | void pthread_mutex_destroy(pthread_mutex_t *mutex){
|
|---|
| 148 | pthread_mutex_t blank;
|
|---|
| 149 | *mutex = blank;
|
|---|
| 150 | }
|
|---|
| 151 |
|
|---|
| 152 |
|
|---|
| 153 | /* pthread_mutex_lock takes in a mutex variable and acts accordingly to its current state and type
|
|---|
| 154 | PTHREAD_MUTEX_NORMAL: Checks to see whether mutex is already locked and behaves accordingly
|
|---|
| 155 | locked and owner: Relock error, returns 0
|
|---|
| 156 | locked and not owner: Waits until mutex is unlocked and then locks and becomes owner
|
|---|
| 157 | unlocked and not owner: Locks the mutex and becomes owner
|
|---|
| 158 | PTHREAD_MUTEX_RECURSIVE
|
|---|
| 159 | */
|
|---|
| 160 | int pthread_mutex_lock(pthread_mutex_t *mutex) {
|
|---|
| 161 | $atomic{
|
|---|
| 162 | if (mutex->kind == PTHREAD_MUTEX_NORMAL){
|
|---|
| 163 | if (mutex->lock != 0)
|
|---|
| 164 | {
|
|---|
| 165 | if(mutex->owner == $proc_null){
|
|---|
| 166 | $when(mutex->lock == 0);
|
|---|
| 167 | }
|
|---|
| 168 | else{
|
|---|
| 169 | if(mutex->owner == $self){
|
|---|
| 170 | $assert($false, "ERROR: Relock attempted");
|
|---|
| 171 | return 0;
|
|---|
| 172 | }
|
|---|
| 173 | else{
|
|---|
| 174 | $when(mutex->lock == 0);
|
|---|
| 175 | }
|
|---|
| 176 | }
|
|---|
| 177 | }
|
|---|
| 178 | mutex->owner = $self;
|
|---|
| 179 | mutex->lock = 1;
|
|---|
| 180 | }
|
|---|
| 181 | else {
|
|---|
| 182 | int tmp = mutex->lock;
|
|---|
| 183 | mutex->lock = 1;
|
|---|
| 184 | if (tmp == 0) { // Attempts lock and checks for whether lock is already locked
|
|---|
| 185 | mutex->count = 1;
|
|---|
| 186 | mutex->owner = $self;
|
|---|
| 187 | }
|
|---|
| 188 | else {
|
|---|
| 189 | //Checks for ownership, otherwise returns error
|
|---|
| 190 | if(mutex->owner == $self)
|
|---|
| 191 | {
|
|---|
| 192 | // Checks for recursive mutex, otherwise returns an error
|
|---|
| 193 | if (mutex->kind == 1) {
|
|---|
| 194 | mutex->count++;
|
|---|
| 195 | if(mutex->count==0){
|
|---|
| 196 | mutex->lock = 0;
|
|---|
| 197 | mutex->owner = $proc_null;
|
|---|
| 198 | }
|
|---|
| 199 | }
|
|---|
| 200 | else {
|
|---|
| 201 | $assert($false);
|
|---|
| 202 | return 0;
|
|---|
| 203 | }
|
|---|
| 204 | }
|
|---|
| 205 | else {
|
|---|
| 206 | $assert($false);
|
|---|
| 207 | return 0;
|
|---|
| 208 | }
|
|---|
| 209 | }
|
|---|
| 210 | }
|
|---|
| 211 | return 0;
|
|---|
| 212 | }
|
|---|
| 213 | }
|
|---|
| 214 |
|
|---|
| 215 |
|
|---|
| 216 | int pthread_mutex_unlock(pthread_mutex_t *mutex) {
|
|---|
| 217 | $atomic{
|
|---|
| 218 | if (mutex->kind == 0 || mutex->kind == 2) {
|
|---|
| 219 | int idx;
|
|---|
| 220 | // Attempts unlock, if already unlocked, returns error
|
|---|
| 221 | if (mutex->lock == 0) {
|
|---|
| 222 | $assert($false, "Attempting to unlock unlocked lock\n");
|
|---|
| 223 | return 0;
|
|---|
| 224 | }
|
|---|
| 225 | else {
|
|---|
| 226 | mutex->lock = 0;
|
|---|
| 227 | mutex->owner = $proc_null;
|
|---|
| 228 | }
|
|---|
| 229 | }
|
|---|
| 230 | else {
|
|---|
| 231 | //Checks for ownership of thread, if not, returns error
|
|---|
| 232 | if(mutex->owner == $self)
|
|---|
| 233 | {
|
|---|
| 234 | //Checks for recursive mutex
|
|---|
| 235 | _Bool tmp = !(mutex->kind == 1);
|
|---|
| 236 | if (--mutex->count == 0){
|
|---|
| 237 | mutex->lock = 0;
|
|---|
| 238 | mutex->owner = $proc_null;
|
|---|
| 239 | }
|
|---|
| 240 | }
|
|---|
| 241 | else {
|
|---|
| 242 | $assert($false);
|
|---|
| 243 | return 0;
|
|---|
| 244 | }
|
|---|
| 245 | }
|
|---|
| 246 | return 0;
|
|---|
| 247 | }
|
|---|
| 248 | }
|
|---|
| 249 |
|
|---|
| 250 |
|
|---|
| 251 | int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex){
|
|---|
| 252 | if(mutex->owner != $self)
|
|---|
| 253 | {
|
|---|
| 254 | printf("Mutex not owned by thread");
|
|---|
| 255 | $assert($false);
|
|---|
| 256 | return 0;
|
|---|
| 257 | }
|
|---|
| 258 | cond->proccount= cond->proccount+1;
|
|---|
| 259 | pthread_mutex_unlock(mutex);
|
|---|
| 260 | $when(cond->signal);
|
|---|
| 261 | cond->signal = 0;
|
|---|
| 262 | --cond->proccount;
|
|---|
| 263 | $when(mutex->lock == 0){pthread_mutex_lock(mutex);}
|
|---|
| 264 | return 0;
|
|---|
| 265 | }
|
|---|
| 266 |
|
|---|
| 267 | int pthread_cond_signal(pthread_cond_t *cond){
|
|---|
| 268 | cond->signal = 1;
|
|---|
| 269 | return 0;
|
|---|
| 270 | }
|
|---|
| 271 |
|
|---|
| 272 | int pthread_cond_broadcast(pthread_cond_t *cond){
|
|---|
| 273 | while(cond->proccount > 0){
|
|---|
| 274 | cond->signal = 1;
|
|---|
| 275 | }
|
|---|
| 276 | return 0;
|
|---|
| 277 | }
|
|---|
| 278 |
|
|---|
| 279 | int pthread_attr_init(pthread_attr_t *attr){
|
|---|
| 280 | attr->stacksize = 0;
|
|---|
| 281 | attr->guardsize = 0;
|
|---|
| 282 | attr->detachstate = PTHREAD_CREATE_DETACHED;
|
|---|
| 283 | //attr->inheritsched = PTHREAD_EXPLICIT_SCHED;
|
|---|
| 284 | //attr->scope = PTHREAD_SCOPE_SYSTEM;
|
|---|
| 285 | attr->stackaddr = NULL;
|
|---|
| 286 | //attr->policy = SCHED_OTHER;
|
|---|
| 287 | return 0;
|
|---|
| 288 | }
|
|---|
| 289 |
|
|---|
| 290 |
|
|---|
| 291 | //Destroy thread attribute
|
|---|
| 292 | int pthread_attr_destroy(pthread_attr_t *attr)
|
|---|
| 293 | {
|
|---|
| 294 | pthread_attr_t *tmp = attr;
|
|---|
| 295 | pthread_attr_t blank;
|
|---|
| 296 | *attr = blank;
|
|---|
| 297 | $free(tmp);
|
|---|
| 298 |
|
|---|
| 299 | }
|
|---|
| 300 |
|
|---|
| 301 | //Set the detachstate attribute
|
|---|
| 302 | int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate)
|
|---|
| 303 | {
|
|---|
| 304 | attr->detachstate = detachstate;
|
|---|
| 305 | return 0;
|
|---|
| 306 | }
|
|---|
| 307 |
|
|---|
| 308 | //Return the detachstate attribute
|
|---|
| 309 | int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate)
|
|---|
| 310 | {
|
|---|
| 311 | *detachstate = attr->detachstate;
|
|---|
| 312 | return 0;
|
|---|
| 313 | }
|
|---|
| 314 |
|
|---|
| 315 | //Set scheduling inheritance
|
|---|
| 316 | int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched)
|
|---|
| 317 | {
|
|---|
| 318 | attr->inheritsched = inheritsched;
|
|---|
| 319 | return 0;
|
|---|
| 320 | }
|
|---|
| 321 |
|
|---|
| 322 | //Return the scheduling inheritance
|
|---|
| 323 | int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched)
|
|---|
| 324 | {
|
|---|
| 325 | *inheritsched = attr->inheritsched;
|
|---|
| 326 | return 0;
|
|---|
| 327 | }
|
|---|
| 328 |
|
|---|
| 329 | /*Set scheduling contention scope
|
|---|
| 330 | int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope)
|
|---|
| 331 | {
|
|---|
| 332 | attr->scope = contentionscope;
|
|---|
| 333 | return 0;
|
|---|
| 334 | }
|
|---|
| 335 |
|
|---|
| 336 | //Return the scheduling contention scope
|
|---|
| 337 | int pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope)
|
|---|
| 338 | {
|
|---|
| 339 | *contentionscope = attr->scope;
|
|---|
| 340 | return 0;
|
|---|
| 341 | }
|
|---|
| 342 | */
|
|---|
| 343 |
|
|---|
| 344 | //Set the starting address of the stack of the thread
|
|---|
| 345 | int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr)
|
|---|
| 346 | {
|
|---|
| 347 | attr->stackaddr = stackaddr;
|
|---|
| 348 | return 0;
|
|---|
| 349 | }
|
|---|
| 350 |
|
|---|
| 351 | //Return the address for the stack
|
|---|
| 352 | int pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr)
|
|---|
| 353 | {
|
|---|
| 354 | *stackaddr = attr->stackaddr;
|
|---|
| 355 | return 0;
|
|---|
| 356 | }
|
|---|
| 357 |
|
|---|
| 358 | //Set stack size
|
|---|
| 359 | int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
|
|---|
| 360 | {
|
|---|
| 361 | attr->stacksize = stacksize;
|
|---|
| 362 | return 0;
|
|---|
| 363 | }
|
|---|
| 364 |
|
|---|
| 365 | //Return the stack size
|
|---|
| 366 | int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize)
|
|---|
| 367 | {
|
|---|
| 368 | *stacksize = attr->stacksize;
|
|---|
| 369 | return 0;
|
|---|
| 370 | }
|
|---|
| 371 |
|
|---|
| 372 | //Set guard size
|
|---|
| 373 | int pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize)
|
|---|
| 374 | {
|
|---|
| 375 | attr->guardsize = guardsize;
|
|---|
| 376 | return 0;
|
|---|
| 377 | }
|
|---|
| 378 |
|
|---|
| 379 | // Return guard size
|
|---|
| 380 | int pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize)
|
|---|
| 381 | {
|
|---|
| 382 | *guardsize = attr->guardsize;
|
|---|
| 383 | return 0;
|
|---|
| 384 | }
|
|---|
| 385 |
|
|---|
| 386 | //Set scheduling policy
|
|---|
| 387 | int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy)
|
|---|
| 388 | {
|
|---|
| 389 | attr->policy = policy;
|
|---|
| 390 | return 0;
|
|---|
| 391 | }
|
|---|
| 392 |
|
|---|
| 393 | // Return scheduling policy
|
|---|
| 394 | int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy)
|
|---|
| 395 | {
|
|---|
| 396 | *policy = attr->policy;
|
|---|
| 397 | return 0;
|
|---|
| 398 | }
|
|---|
| 399 |
|
|---|
| 400 |
|
|---|
| 401 |
|
|---|
| 402 |
|
|---|
| 403 |
|
|---|