| 1 | #include <pthread_extra.h> |
| 2 | #include <time.h> |
| 3 | #include <stdio.h> |
| 4 | #include <stdbool.h> |
| 5 | |
| 6 | /* |
| 7 | //This is first prototype for two mutexes only, it is useful in order to understand how this all works |
| 8 | //Currently it was replaced by macro with the same name |
| 9 | int pthread_mutex_timedlock_two(pthread_mutex_t *a, pthread_mutex_t *b, const struct timespec *restrict abs_timeout) { |
| 10 | int ret; |
| 11 | |
| 12 | while(1) { |
| 13 | //Wait for the first mutex |
| 14 | ret = (abs_timeout==NULL ? pthread_mutex_lock(a) : pthread_mutex_timedlock(a, abs_timeout)); |
| 15 | if(ret) return ret; //Something is fishy about this mutex. Abort! |
| 16 | |
| 17 | //Try to lock the second mutex |
| 18 | ret = pthread_mutex_trylock(b); |
| 19 | if(!ret) return ret; //Locked BOTH Hooray! |
| 20 | |
| 21 | //Unlock first if second failed to prevent deadlocks |
| 22 | pthread_mutex_unlock(a); |
| 23 | |
| 24 | //Swap mutexes, so we will try to block on the second mutex next time: |
| 25 | pthread_mutex_swap(a, b); |
| 26 | //printf("Retry!\n"); |
| 27 | } |
| 28 | } |
| 29 | */ |
| 30 | |
| 31 | int pthread_mutex_timedlock_multi_generic(pthread_mutex_t **lck, int cnt, bool block, const struct timespec *restrict abs_timeout) { |
| 32 | int ret, locked; |
| 33 | |
| 34 | while(1) { |
| 35 | //Try to lock all mutexes |
| 36 | for(int i = 0; i<cnt; i++) { |
| 37 | //Block only on the first one |
| 38 | if(block && i==0) { |
| 39 | ret = (abs_timeout==NULL ? pthread_mutex_lock(lck[i]) : pthread_mutex_timedlock(lck[i], abs_timeout)); |
| 40 | if(ret) return ret; //Something went wrong |
| 41 | continue; |
| 42 | } |
| 43 | //Then try if we can lock the rest |
| 44 | ret = pthread_mutex_trylock(lck[i]); |
| 45 | if(ret) { |
| 46 | //Cannot lock this one |
| 47 | locked = i; |
| 48 | printf("Cannot lock #%d!\n", i); |
| 49 | break; |
| 50 | } |
| 51 | locked = i; |
| 52 | } |
| 53 | |
| 54 | //Check if we managed to lock all locks |
| 55 | if(locked == cnt) return 0; |
| 56 | |
| 57 | //Unlock all mutexes that we managed to lock so far |
| 58 | for(int i = 0;i<locked;i++) { |
| 59 | printf("Unlocking #%d\n", i); |
| 60 | pthread_mutex_unlock(lck[i]); |
| 61 | } |
| 62 | if(!block) return ret; //We do not want to block, just trying |
| 63 | |
| 64 | //Try to block on locked mutex in next round |
| 65 | pthread_mutex_swap(lck[0],lck[locked]); |
| 66 | } |
| 67 | } |