| WITH LOCK | |
| ********* | |
| create clock id: | |
| id->state = OK; | |
| waiting for id: | |
| lock | |
| /* once unscheduled, the id cannot be used anymore */ | |
| while (id->state != unscheduled) { | |
| id->state = busy; | |
| unlock | |
| ret = gstpoll (timeout); | |
| lock | |
| if (id->state == unscheduled) { | |
| /* id became unscheduled, read the fd and broadcast */ | |
| read (fd) | |
| cond_broadcast () | |
| } | |
| else { | |
| if (ret != 0) { | |
| /* some other id got unlocked */ | |
| /* mark ourselves as EARLY, we release the lock and we could be | |
| * unscheduled ourselves but we don't want the unscheduling thread | |
| * to write on the fd */ | |
| id->state = EARLY; | |
| /* wait until it reads the fd and signals us */ | |
| cond_wait () | |
| } | |
| else { | |
| /* we timed out */ | |
| id->state = OK | EARLY; | |
| } | |
| } | |
| } | |
| unlock | |
| return id->state; | |
| unschedule id: | |
| lock | |
| /* if it's busy waiting in poll, write to the fd */ | |
| if (id->state == busy) { | |
| write (fd) | |
| } | |
| /* when it leaves the poll, it'll detect the unscheduled. */ | |
| id->state = unscheduled; | |
| unlock | |
| ATOMIC | |
| ****** | |
| create clock id: | |
| id->state = OK; | |
| waiting for id: | |
| /* once state changes to != OK, the id cannot be used anymore */ | |
| while (g_atomic_int_compare_and_exchange (&id->state, OK, BUSY) { | |
| ret = gstpoll (timeout); | |
| /* two things can happen here, either the entry is BUSY or UNSCHEDULED, | |
| * first check if it was busy. */ | |
| if (g_atomic_int_compare_and_exchange (&id->state, BUSY, OK) { | |
| /* we got unscheduled, see if it was because we timed out or some other | |
| * id got unscheduled */ | |
| if (ret != 0) { | |
| if (g_atomic_int_get (&waiters) > 0) { | |
| lock | |
| /* some other id got unlocked */ | |
| /* wait until it reads the fd and signals us */ | |
| while (waiters) | |
| cond_wait () | |
| unlock | |
| } | |
| } | |
| else { | |
| /* we timed out update the status. */ | |
| id->state = OK | EARLY; | |
| break; | |
| } | |
| } | |
| else if (g_atomic_int_get (&id->state) == UNSCHEDULED) { | |
| /* id became unscheduled, read the fd and broadcast */ | |
| lock | |
| read (fd) | |
| g_atomic_int_dec (&waiters); | |
| cond_broadcast () | |
| unlock | |
| break; | |
| } | |
| else { | |
| g_assert_not_reached (); | |
| } | |
| } | |
| return id->state; | |
| unschedule id: | |
| if (g_atomic_int_compare_and_exchange (&id->state, BUSY, UNSCHEDULED) { | |
| /* if it's busy waiting in poll, write to the fd */ | |
| lock | |
| g_atomic_int_inc (&waiters) | |
| write (fd) | |
| unlock | |
| } | |
| else { | |
| /* was not waiting, just mark unscheduled */ | |
| g_atomic_int_set (id->state, UNSCHEDULED); | |
| } |