zoukankan      html  css  js  c++  java
  • lock

    #ifndef lock_h
    #define lock_h
    
    #include <stdint.h>
    #include <string.h>
    #include "mydef.h"
    #include "now.h"
    #define debug_lock 1
    
    typedef struct {
        intptr_t lck;
        uintptr_t tid;
        uintptr_t nr;
    #if debug_lock
        const char* file;
        uintptr_t line;
    #endif
    } lock_t;
    
    #define lock_initial {0}
    #define lock_initial_locked {1, 0, 1}
    static __attribute__((unused)) lock_t lock_val = lock_initial;
    
    #if (debug_lock == 2)
    #define locktrace_begin() uintptr_t tms = now();
    #define lock_backtrace(lkp) 
    do { 
        uintptr_t current = now(); 
        if (tms == 0) { 
            tms = current; 
        } 
        
        if (current > tms + 3000) { 
            tms = current - 2000; 
            logmsg("locktrace: %d %s:%d
    ", (int) lkp->lck, lkp->file, (int) lkp->line); 
        } 
    } while (0)
    #else
    #define locktrace_begin() (void) 0
    #define lock_backtrace(x) (void) 0
    #endif
    
    #if debug_lock
        #define log_lock(ptr, l, f) do {ptr->line = l; ptr->file = f;} while (0)
        #define log_unlock(ptr) do {ptr->line = -1; ptr->file = "";} while (0)
    #else
        #define log_lock(ptr, l, f) (void) (0)
        #define log_unlock(ptr) (void) (0)
    #endif
    
    #ifdef __linux__
        #ifndef _GNU_SOURCE
        #define _GNU_SOURCE
        #endif
    
        #define my_lock(lkp, re) 
        do {  
            lock_t* ptr = lkp; 
            if (!__sync_bool_compare_and_swap(&ptr->lck, 0, 1)) { 
                if (ptr->lck == 2) { 
                    syscall(__NR_futex, &ptr->lck, FUTEX_WAIT, 2, NULL, NULL, 0); 
                } 
                
                locktrace_begin(); 
                while (0 != __sync_lock_test_and_set(&ptr->lck, 2)) { 
                    syscall(__NR_futex, &ptr->lck, FUTEX_WAIT, 2, NULL, NULL, 0); 
                    lock_backtrace(ptr); 
                } 
            } 
            my_assert2(ptr->lck != 0, "lck = %d", ptr->lck); 
            my_assert2(ptr->nr == 0, "lck = %d, nr = %d, %d@%s", ptr->lck, ptr->nr, ptr->line, ptr->file); 
            log_lock(ptr, __LINE__, __FILE__); 
            
            my_assert(ptr->tid == 0); 
            if (re) { 
                ptr->tid = systid(); 
            } 
            ++ptr->nr; 
        } while (0)
    
        #define unlock(lkp) 
        do { 
            lock_t* ptr = lkp; 
            my_assert2(ptr->lck != 0, "lck = %d, nr = %d", ptr->lck, ptr->nr); 
            --ptr->nr; 
            wmb(); 
            if (ptr->nr > 0) { 
                my_assert2(ptr->tid != 0, "tid != 0, ptr->nr = %d, lck = %d, %d@%s", ptr->nr, ptr->lck, ptr->line, ptr->file); 
            } else { 
                ptr->tid = 0; 
                /* wmb(); */ 
                log_unlock(ptr); 
                if (2 == __sync_lock_test_and_set(&ptr->lck, 0)) { 
                    while (-1 == syscall(__NR_futex, &ptr->lck, FUTEX_WAKE, 1, NULL, NULL, 0)); 
                } 
            } 
        } while (0)
    
    #else
        #define my_lock(lkp, re) 
        do {  
            lock_t* ptr = lkp; 
            locktrace_begin(); 
            while (!__sync_bool_compare_and_swap((void **) &ptr->lck, (void *) 0, (void *) 1)) { 
                sched_yield();  
                lock_backtrace(ptr); 
            } 
            log_lock(ptr, __LINE__, __FILE__); 
            
            my_assert(ptr->tid == 0); 
            if (re) { 
                ptr->tid = systid(); 
            } 
            ++ptr->nr; 
        } while (0)
    
        #define unlock(lkp) 
        do { 
            lock_t* ptr = lkp; 
            my_assert(ptr->lck != 0); 
            --ptr->nr; 
            wmb(); 
            if (ptr->nr > 0) { 
                my_assert(ptr->tid != 0); 
            } else { 
                ptr->tid = 0; 
                /* wmb(); */ 
                log_unlock(ptr); 
                ptr->lck = 0; 
            } 
        } while (0)
    #endif
    
    #define lock(lkp) my_lock(lkp, 0)
    
    #define relock(lkp) 
    do {  
        lock_t* ptr = lkp; 
        /* this rmb() is here to assure to see ptr->tid = 0 in unlock */ 
        /* if thread exit after unlock(), then another thread is spwaned with same tid */ 
        /* on another cpu core and then call lock_recursive. */ 
        /* all the above happens so quickly that the other cpu core does not see ptr->tid = 0 */ 
        /* it is so impossible to happen that I comment the "correct" implemention. */ 
        /* rmb(); */ 
        
        if (ptr->tid == systid()) { 
            /* if true, it's same thread, event in another cpu core, no mb() is needed. */ 
            ++ptr->nr; 
        } else { 
            my_lock(lkp, 1); 
        } 
    } while (0)
    
    static __attribute__((unused)) inline intptr_t my_try_lock(lock_t* lkp, uintptr_t re, uintptr_t line, const char* file)
    {
        if (!__sync_bool_compare_and_swap((void **) &((lkp)->lck), (void *) 0, (void *) 1)) {
            return -1;
        }
        log_lock(lkp, line, file);
    
        my_assert(lkp->tid == 0);
        if (re) {
            lkp->tid = systid();
        }
        ++lkp->nr;
        return 0;
    }
    
    #define try_lock(lkp) my_try_lock(lkp, 0, __LINE__, __FILE__)
    #define retry_lock(lkp) my_try_lock(lkp, 1, __LINE__, __FILE__)
    
    typedef struct {
        intptr_t nr;
    } rwlock_t;
    
    #define read_write_max 8000
    #define rw_lock_initial {read_write_max}
    static __attribute__((unused)) rwlock_t rw_lock_val = rw_lock_initial;
    
    #define read_write_lock(lckp, val) 
    do { 
        rwlock_t* lck = lckp; 
        do { 
            intptr_t n = __sync_sub_and_fetch(&lck->nr, val); 
            if (n >= 0) { 
                break; 
            } 
            __sync_add_and_fetch(&lck->nr, val); 
            sched_yield(); 
        } while (1); 
    } while (0)
    
    #define read_write_unlock(lckp, val) 
    do { 
        rwlock_t* lck = lckp; 
        __sync_add_and_fetch(&lck->nr, val); 
    } while (0)
    
    #define read_lock(lckp) read_write_lock(lckp, 1)
    #define write_lock(lckp) read_write_lock(lckp, read_write_max)
    #define read_unlock(lckp) read_write_unlock(lckp, 1)
    #define write_unlock(lckp) read_write_unlock(lckp, read_write_max)
    
    #endif
    
  • 相关阅读:
    Maximum sum
    走出迷宫
    取石子游戏
    全排列
    BZOJ3456 城市规划
    【SHOI2016】黑暗前的幻想乡
    【AHOI2012】信号塔
    HDU5730 Shell Necklace
    线性常系数齐次递推关系学习笔记
    矩阵树定理学习笔记
  • 原文地址:https://www.cnblogs.com/zylthinking/p/5975731.html
Copyright © 2011-2022 走看看