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