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); }