Changeset 1b7eec9 in mainline


Ignore:
Timestamp:
2012-12-04T03:48:21Z (12 years ago)
Author:
Adam Hraska <adam.hraska+hos@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
9a3b469
Parents:
cb10bc9
Message:

urcu: rcu_synchronize allows to specify if it may block the current fibril or rather the current thread.

Location:
uspace/lib
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/include/futex.h

    rcb10bc9 r1b7eec9  
    4040#include <libc.h>
    4141
    42 
    43 #define FUTEX_INITIALIZER  {{1}}
     42#define FUTEX_INITIALIZE(val) {{(val)}}
     43#define FUTEX_INITIALIZER     FUTEX_INITIALIZE(1)
    4444
    4545typedef struct futex {
  • uspace/lib/c/include/sys/time.h

    rcb10bc9 r1b7eec9  
    7979
    8080extern void udelay(useconds_t);
     81extern int usleep(useconds_t);
    8182
    8283extern time_t mktime(struct tm *tm);
  • uspace/lib/urcu/rcu.c

    rcb10bc9 r1b7eec9  
    7878#include <smp_memory_barrier.h>
    7979#include <assert.h>
     80#include <time.h>
    8081
    8182
     
    99100/** Process global RCU data. */
    100101typedef struct rcu_data {
    101         fibril_mutex_t mtx;
    102102        size_t cur_gp;
    103103        size_t reader_group;
    104104        futex_t list_futex;
    105105        list_t fibrils_list;
     106        struct {
     107                futex_t futex;
     108                bool locked;
     109                list_t blocked_fibrils;
     110                size_t blocked_thread_cnt;
     111                futex_t futex_blocking_threads;
     112        } sync_lock;
    106113} rcu_data_t;
     114
     115typedef struct blocked_fibril {
     116        fid_t id;
     117        link_t link;
     118        bool is_ready;
     119} blocked_fibril_t;
    107120
    108121
     
    119132/** Process global RCU data. */
    120133static rcu_data_t rcu = {
    121         .mtx = FIBRIL_MUTEX_INITIALIZER(rcu.mtx),
    122134        .cur_gp = 0,
    123135        .reader_group = RCU_GROUP_A,
    124136        .list_futex = FUTEX_INITIALIZER,
    125137        .fibrils_list = LIST_INITIALIZER(rcu.fibrils_list),
     138        .sync_lock = {
     139                .futex = FUTEX_INITIALIZER,
     140                .locked = false,
     141                .blocked_fibrils = LIST_INITIALIZER(rcu.sync_lock.blocked_fibrils),
     142                .blocked_thread_cnt = 0,
     143                .futex_blocking_threads = FUTEX_INITIALIZE(0),
     144        },
    126145};
    127146
    128147
    129 static void wait_for_readers(size_t reader_group);
     148static void wait_for_readers(size_t reader_group, blocking_mode_t blocking_mode);
    130149static void force_mb_in_all_threads(void);
    131150static bool is_preexisting_reader(const fibril_rcu_data_t *fib, size_t group);
     151
     152static void lock_sync(blocking_mode_t blocking_mode);
     153static void unlock_sync(void);
     154static void sync_sleep(blocking_mode_t blocking_mode);
    132155
    133156static bool is_in_group(size_t nesting_cnt, size_t group);
     
    145168        assert(!fibril_rcu.registered);
    146169       
    147         futex_down(&rcu.list_futex);
     170        _futex_down(&rcu.list_futex);
    148171        list_append(&fibril_rcu.link, &rcu.fibrils_list);
    149         futex_up(&rcu.list_futex);
     172        _futex_up(&rcu.list_futex);
    150173       
    151174        fibril_rcu.registered = true;
     
    170193        fibril_rcu.nesting_cnt = 0;
    171194       
    172         futex_down(&rcu.list_futex);
     195        _futex_down(&rcu.list_futex);
    173196        list_remove(&fibril_rcu.link);
    174         futex_up(&rcu.list_futex);
     197        _futex_up(&rcu.list_futex);
    175198
    176199        fibril_rcu.registered = false;
     
    214237
    215238/** Blocks until all preexisting readers exit their critical sections. */
    216 void rcu_synchronize(void)
     239void _rcu_synchronize(blocking_mode_t blocking_mode)
    217240{
    218241        assert(!rcu_read_locked());
     
    224247        size_t gp_in_progress = ACCESS_ONCE(rcu.cur_gp);
    225248       
    226         /* todo: early exit for batched sync()s */
    227         fibril_mutex_lock(&rcu.mtx);
     249        lock_sync(blocking_mode);
    228250       
    229251        /*
     
    236258        /* rcu.cur_gp >= gp_in_progress + 2, but tolerates overflows. */
    237259        if (rcu.cur_gp != gp_in_progress && rcu.cur_gp + 1 != gp_in_progress) {
    238                 fibril_mutex_unlock(&rcu.mtx);
     260                unlock_sync();
    239261                return;
    240262        }
     
    273295       
    274296        size_t new_reader_group = get_other_group(rcu.reader_group);
    275         wait_for_readers(new_reader_group);
     297        wait_for_readers(new_reader_group, blocking_mode);
    276298       
    277299        /* Separates waiting for readers in new_reader_group from group flip. */
     
    285307        memory_barrier();
    286308       
    287         wait_for_readers(old_reader_group);
     309        wait_for_readers(old_reader_group, blocking_mode);
    288310       
    289311        /* MB_FORCE_U  */
    290312        force_mb_in_all_threads(); /* MB_FORCE_U */
    291313       
    292         fibril_mutex_unlock(&rcu.mtx);
     314        unlock_sync();
    293315}
    294316
     
    305327
    306328/** Waits for readers of reader_group to exit their readers sections. */
    307 static void wait_for_readers(size_t reader_group)
    308 {
    309         futex_down(&rcu.list_futex);
     329static void wait_for_readers(size_t reader_group, blocking_mode_t blocking_mode)
     330{
     331        _futex_down(&rcu.list_futex);
    310332       
    311333        list_t quiescent_fibrils;
     
    318340                       
    319341                        if (is_preexisting_reader(fib, reader_group)) {
    320                                 futex_up(&rcu.list_futex);
    321                                 async_usleep(RCU_SLEEP_MS * 1000);
    322                                 futex_down(&rcu.list_futex);
     342                                _futex_up(&rcu.list_futex);
     343                                sync_sleep(blocking_mode);
     344                                _futex_down(&rcu.list_futex);
     345                                /* Break to while loop. */
    323346                                break;
    324347                        } else {
     
    330353       
    331354        list_concat(&rcu.fibrils_list, &quiescent_fibrils);
    332         futex_up(&rcu.list_futex);
    333 }
     355        _futex_up(&rcu.list_futex);
     356}
     357
     358static void lock_sync(blocking_mode_t blocking_mode)
     359{
     360        _futex_down(&rcu.sync_lock.futex);
     361        if (rcu.sync_lock.locked) {
     362                if (blocking_mode == BM_BLOCK_FIBRIL) {
     363                        blocked_fibril_t blocked_fib;
     364                        blocked_fib.id = fibril_get_id();
     365                               
     366                        list_append(&blocked_fib.link, &rcu.sync_lock.blocked_fibrils);
     367                       
     368                        do {
     369                                blocked_fib.is_ready = false;
     370                                _futex_up(&rcu.sync_lock.futex);
     371                                fibril_switch(FIBRIL_TO_MANAGER);
     372                                _futex_down(&rcu.sync_lock.futex);
     373                        } while (rcu.sync_lock.locked);
     374                       
     375                        list_remove(&blocked_fib.link);
     376                        rcu.sync_lock.locked = true;
     377                } else {
     378                        assert(blocking_mode == BM_BLOCK_THREAD);
     379                        rcu.sync_lock.blocked_thread_cnt++;
     380                        _futex_up(&rcu.sync_lock.futex);
     381                        _futex_down(&rcu.sync_lock.futex_blocking_threads);
     382                }
     383        } else {
     384                rcu.sync_lock.locked = true;
     385        }
     386}
     387
     388static void unlock_sync(void)
     389{
     390        assert(rcu.sync_lock.locked);
     391       
     392        /*
     393         * Blocked threads have a priority over fibrils when accessing sync().
     394         * Pass the lock onto a waiting thread.
     395         */
     396        if (0 < rcu.sync_lock.blocked_thread_cnt) {
     397                --rcu.sync_lock.blocked_thread_cnt;
     398                _futex_up(&rcu.sync_lock.futex_blocking_threads);
     399        } else {
     400                /* Unlock but wake up any fibrils waiting for the lock. */
     401               
     402                if (!list_empty(&rcu.sync_lock.blocked_fibrils)) {
     403                        blocked_fibril_t *blocked_fib = member_to_inst(
     404                                list_first(&rcu.sync_lock.blocked_fibrils), blocked_fibril_t, link);
     405       
     406                        if (!blocked_fib->is_ready) {
     407                                blocked_fib->is_ready = true;
     408                                fibril_add_ready(blocked_fib->id);
     409                        }
     410                }
     411               
     412                rcu.sync_lock.locked = false;
     413                _futex_up(&rcu.sync_lock.futex);
     414        }
     415}
     416
     417static void sync_sleep(blocking_mode_t blocking_mode)
     418{
     419        assert(rcu.sync_lock.locked);
     420        /*
     421         * Release the futex to avoid deadlocks in singlethreaded apps
     422         * but keep sync locked.
     423         */
     424        _futex_up(&rcu.sync_lock.futex);
     425
     426        if (blocking_mode == BM_BLOCK_FIBRIL) {
     427                async_usleep(RCU_SLEEP_MS * 1000);
     428        } else {
     429                usleep(RCU_SLEEP_MS * 1000);
     430        }
     431               
     432        _futex_down(&rcu.sync_lock.futex);
     433}
     434
    334435
    335436static bool is_preexisting_reader(const fibril_rcu_data_t *fib, size_t group)
  • uspace/lib/urcu/rcu.h

    rcb10bc9 r1b7eec9  
    9292#define rcu_access(ptr) ACCESS_ONCE(ptr)
    9393
     94typedef enum blocking_mode {
     95        BM_BLOCK_FIBRIL,
     96        BM_BLOCK_THREAD
     97} blocking_mode_t;
    9498
    9599extern void rcu_register_fibril(void);
     
    101105extern bool rcu_read_locked(void);
    102106
    103 extern void rcu_synchronize(void);
     107#define rcu_synchronize() _rcu_synchronize(BM_BLOCK_FIBRIL)
     108
     109extern void _rcu_synchronize(blocking_mode_t);
    104110
    105111#endif
Note: See TracChangeset for help on using the changeset viewer.