Fork us on GitHub Follow us on Facebook Follow us on Twitter

Changeset a55d76b1 in mainline


Ignore:
Timestamp:
2018-06-13T17:07:58Z (3 years ago)
Author:
Jiří Zárevúcky <jiri.zarevucky@…>
Branches:
master
Children:
be2a20ac, c407b98
Parents:
899342e
git-author:
Jiří Zárevúcky <jiri.zarevucky@…> (2018-06-13 17:04:01)
git-committer:
Jiří Zárevúcky <jiri.zarevucky@…> (2018-06-13 17:07:58)
Message:

Implement a simple counting semaphore for fibrils.

Location:
uspace/lib/c
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/fibril_synch.c

    r899342e ra55d76b1  
    629629}
    630630
     631/**
     632 * Initialize a semaphore with initial count set to the provided value.
     633 *
     634 * @param sem    Semaphore to initialize.
     635 * @param count  Initial count. Must not be negative.
     636 */
     637void fibril_semaphore_initialize(fibril_semaphore_t *sem, long count)
     638{
     639        /*
     640         * Negative count denotes the length of waitlist,
     641         * so it makes no sense as an initial value.
     642         */
     643        assert(count >= 0);
     644        sem->count = count;
     645        list_initialize(&sem->waiters);
     646}
     647
     648/**
     649 * Produce one token.
     650 * If there are fibrils waiting for tokens, this operation satisfies
     651 * exactly one waiting `fibril_semaphore_down()`.
     652 * This operation never blocks the fibril.
     653 *
     654 * @param sem  Semaphore to use.
     655 */
     656void fibril_semaphore_up(fibril_semaphore_t *sem)
     657{
     658        futex_down(&async_futex);
     659        sem->count++;
     660
     661        if (sem->count > 0) {
     662                futex_up(&async_futex);
     663                return;
     664        }
     665
     666        link_t *tmp = list_first(&sem->waiters);
     667        assert(tmp);
     668        list_remove(tmp);
     669
     670        futex_up(&async_futex);
     671
     672        awaiter_t *wdp = list_get_instance(tmp, awaiter_t, wu_event.link);
     673        fibril_add_ready(wdp->fid);
     674        optimize_execution_power();
     675}
     676
     677/**
     678 * Consume one token.
     679 * If there are no available tokens (count <= 0), this operation blocks until
     680 * another fibril produces a token using `fibril_semaphore_up()`.
     681 *
     682 * @param sem  Semaphore to use.
     683 */
     684void fibril_semaphore_down(fibril_semaphore_t *sem)
     685{
     686        futex_down(&async_futex);
     687        sem->count--;
     688
     689        if (sem->count >= 0) {
     690                futex_up(&async_futex);
     691                return;
     692        }
     693
     694        awaiter_t wdata;
     695        awaiter_initialize(&wdata);
     696
     697        wdata.fid = fibril_get_id();
     698        list_append(&wdata.wu_event.link, &sem->waiters);
     699        fibril_switch(FIBRIL_TO_MANAGER);
     700
     701        /* async_futex not held after fibril_switch() */
     702}
     703
    631704/** @}
    632705 */
  • uspace/lib/c/include/fibril_synch.h

    r899342e ra55d76b1  
    143143} fibril_timer_t;
    144144
     145/** A counting semaphore for fibrils. */
     146typedef struct {
     147        long count;
     148        list_t waiters;
     149} fibril_semaphore_t;
     150
     151#define FIBRIL_SEMAPHORE_INITIALIZER(name, cnt) \
     152        { \
     153                .count = (cnt), \
     154                .waiters = { \
     155                        .head = { \
     156                                .next = &(name).waiters.head, \
     157                                .prev = &(name).waiters.head, \
     158                        } \
     159                } \
     160        }
     161
     162#define FIBRIL_SEMAPHORE_INITIALIZE(name, cnt) \
     163        fibril_semaphore_t name = FIBRIL_SEMAPHORE_INITIALIZER(name, cnt)
     164
    145165extern void fibril_mutex_initialize(fibril_mutex_t *);
    146166extern void fibril_mutex_lock(fibril_mutex_t *);
     
    174194extern fibril_timer_state_t fibril_timer_clear_locked(fibril_timer_t *);
    175195
     196extern void fibril_semaphore_initialize(fibril_semaphore_t *, long);
     197extern void fibril_semaphore_up(fibril_semaphore_t *);
     198extern void fibril_semaphore_down(fibril_semaphore_t *);
     199
    176200#endif
    177201
Note: See TracChangeset for help on using the changeset viewer.