Ticket #8798: 0001-pthread_rwlock-local-implementation-with-mutexes.patch

File 0001-pthread_rwlock-local-implementation-with-mutexes.patch, 8.3 KB (added by korli, 7 years ago)

reworked patch for local pthread_rwlock

  • headers/posix/pthread.h

    From 17ec186672d5184fa89bf4360b7922c1ce4ca6e3 Mon Sep 17 00:00:00 2001
    From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Duval?= <jerome.duval@gmail.com>
    Date: Tue, 30 May 2017 22:30:06 +0200
    Subject: [PATCH] pthread_rwlock: local implementation with mutexes.
    
    * add PTHREAD_RWLOCK_INITIALIZER macro to statically initialize.
    ---
     headers/posix/pthread.h                            |   2 +
     headers/posix/sys/types.h                          |  12 +-
     .../libroot/posix/pthread/pthread_rwlock.cpp       | 202 +++++++++------------
     3 files changed, 99 insertions(+), 117 deletions(-)
    
    diff --git a/headers/posix/pthread.h b/headers/posix/pthread.h
    index 489aace..e55ee62 100644
    a b extern "C" {  
    8080    { PTHREAD_MUTEX_RECURSIVE, 0, -42, -1, 0 }
    8181#define PTHREAD_COND_INITIALIZER    \
    8282    { 0, -42, NULL, 0, 0 }
     83#define PTHREAD_RWLOCK_INITIALIZER  \
     84    { 0, -1, 0, 0, 0, 0, 0, 0 }
    8385
    8486/* mutex functions */
    8587extern int pthread_mutex_destroy(pthread_mutex_t *mutex);
  • headers/posix/sys/types.h

    diff --git a/headers/posix/sys/types.h b/headers/posix/sys/types.h
    index b09aba5..4fb7ec8 100644
    a b struct _pthread_rwlock {  
    108108            __haiku_std_int32   sem;
    109109        } shared;
    110110        struct {
    111             __haiku_std_int32   lock_sem;
    112             __haiku_std_int32   lock_count;
     111            __haiku_std_int32   mutex;
    113112            __haiku_std_int32   reader_count;
    114             __haiku_std_int32   writer_count;
    115             void*               waiters[2];
     113            __haiku_std_int32   write_waiter_count;
     114            __haiku_std_int32   write_lock;
     115            __haiku_std_int32   read_waiter_count;
     116            __haiku_std_int32   read_lock;
     117#ifdef B_HAIKU_64_BIT
     118            __haiku_std_int32   unused[2];
     119#endif
    116120        } local;
    117121    } u;
    118122};
  • src/system/libroot/posix/pthread/pthread_rwlock.cpp

    diff --git a/src/system/libroot/posix/pthread/pthread_rwlock.cpp b/src/system/libroot/posix/pthread/pthread_rwlock.cpp
    index 65e83be..0243100 100644
    a b  
    1616#include <util/DoublyLinkedList.h>
    1717
    1818#include "pthread_private.h"
     19#include <user_mutex_defs.h>
    1920
    2021
    2122#define MAX_READER_COUNT    1000000
    struct SharedRWLock {  
    9394struct LocalRWLock {
    9495    uint32_t    flags;
    9596    int32_t     owner;
    96     int32_t     lock_sem;
    97     int32_t     lock_count;
     97    int32_t     mutex;
    9898    int32_t     reader_count;
    99     int32_t     writer_count;
    100         // Note, that reader_count and writer_count are not used the same way.
    101         // writer_count includes the write lock owner as well as waiting
    102         // writers. reader_count includes read lock owners only.
    103     WaiterList  waiters;
     99    int32_t     write_waiter_count;
     100    int32_t     write_lock;
     101    int32_t     read_waiter_count;
     102    int32_t     read_lock;
    104103
    105104    status_t Init()
    106105    {
    107106        flags = 0;
    108107        owner = -1;
    109         lock_sem = create_sem(0, "pthread rwlock");
    110         lock_count = 1;
     108        mutex = 0;
    111109        reader_count = 0;
    112         writer_count = 0;
    113         new(&waiters) WaiterList;
    114 
    115         return lock_sem >= 0 ? B_OK : EAGAIN;
     110        write_waiter_count = 0;
     111        write_lock = 0;
     112        read_waiter_count = 0;
     113        read_lock = 0;
     114        return B_OK;
    116115    }
    117116
    118117    status_t Destroy()
    119118    {
    120         if (lock_sem < 0)
    121             return B_BAD_VALUE;
    122         return delete_sem(lock_sem) == B_OK ? B_OK : B_BAD_VALUE;
     119        Locker locker(this);
     120        if (reader_count > 0 || owner != -1 || read_waiter_count > 0
     121            || write_waiter_count > 0)
     122            return EBUSY;
     123        return 0;
    123124    }
    124125
    125126    bool StructureLock()
    126127    {
    127         if (atomic_add((int32*)&lock_count, -1) <= 0)
    128             acquire_sem(lock_sem);
     128        // Enter critical region: lock the mutex
     129        int32 status = atomic_or((int32*)&mutex, B_USER_MUTEX_LOCKED);
     130
     131        // If already locked, call the kernel
     132        if ((status & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) != 0) {
     133            do {
     134                status = _kern_mutex_lock((int32*)&mutex, NULL, 0, 0);
     135            } while (status == B_INTERRUPTED);
     136
     137            if (status != B_OK)
     138                return false;
     139        }
    129140        return true;
    130141    }
    131142
    132143    void StructureUnlock()
    133144    {
    134         if (atomic_add((int32*)&lock_count, 1) < 0)
    135             release_sem(lock_sem);
     145        // Exit critical region: unlock the mutex
     146        int32 status = atomic_and((int32*)&mutex,
     147            ~(int32)B_USER_MUTEX_LOCKED);
     148
     149        if ((status & B_USER_MUTEX_WAITING) != 0)
     150            _kern_mutex_unlock((int32*)&mutex, 0);
    136151    }
    137152
    138153    status_t ReadLock(bigtime_t timeout)
    139154    {
    140155        Locker locker(this);
    141156
    142         if (writer_count == 0) {
    143             reader_count++;
    144             return B_OK;
     157        status_t status = B_OK;
     158        if (owner != -1 || write_waiter_count > 0) {
     159            if (timeout == 0)
     160                return B_TIMED_OUT;
     161            read_waiter_count++;
     162            do {
     163                atomic_or((int32*)&read_lock, B_USER_MUTEX_LOCKED);
     164                status = _kern_mutex_switch_lock((int32*)&mutex,
     165                    (int32*)&read_lock, "pthread rwlock",
     166                    timeout == B_INFINITE_TIMEOUT ? 0 : B_ABSOLUTE_REAL_TIME_TIMEOUT,
     167                    timeout);
     168                StructureLock();
     169                if (status != 0)
     170                    break;
     171            } while (owner != -1 || write_waiter_count > 0);
     172            read_waiter_count--;
    145173        }
    146174
    147         return _Wait(false, timeout);
     175        if (status == 0)
     176            reader_count++;
     177
     178        return status;
    148179    }
    149180
    150181    status_t WriteLock(bigtime_t timeout)
    151182    {
    152183        Locker locker(this);
    153184
    154         if (reader_count == 0 && writer_count == 0) {
    155             writer_count++;
     185        status_t status = B_OK;
     186        if (reader_count > 0 || owner != -1) {
     187            if (timeout == 0)
     188                return B_TIMED_OUT;
     189            write_waiter_count++;
     190            do {
     191                atomic_or((int32*)&write_lock, B_USER_MUTEX_LOCKED);
     192                status = _kern_mutex_switch_lock((int32*)&mutex,
     193                    (int32*)&write_lock, "pthread rwlock",
     194                    timeout == B_INFINITE_TIMEOUT ? 0 : B_ABSOLUTE_REAL_TIME_TIMEOUT,
     195                    timeout);
     196                StructureLock();
     197                if (status != 0)
     198                    break;
     199            } while (reader_count > 0 || owner != -1);
     200            write_waiter_count--;
     201            if (status == B_TIMED_OUT && write_waiter_count == 0
     202                && read_waiter_count > 0) {
     203                _kern_mutex_unlock((int32*)&read_lock,
     204                    B_USER_MUTEX_UNBLOCK_ALL);
     205            }
     206        }
     207        if (status == 0) {
    156208            owner = find_thread(NULL);
    157             return B_OK;
    158209        }
    159 
    160         return _Wait(true, timeout);
     210        return status;
    161211    }
    162212
    163213    status_t Unlock()
    struct LocalRWLock {  
    165215        Locker locker(this);
    166216
    167217        if (find_thread(NULL) == owner) {
    168             writer_count--;
    169218            owner = -1;
    170         } else
     219            if (write_waiter_count > 0)
     220                _kern_mutex_unlock((int32*)&write_lock, 0);
     221            else if (read_waiter_count > 0)
     222                _kern_mutex_unlock((int32*)&read_lock, B_USER_MUTEX_UNBLOCK_ALL);
     223        } else {
    171224            reader_count--;
    172 
    173         _Unblock();
     225            if (reader_count == 0 && write_waiter_count > 0)
     226                _kern_mutex_unlock((int32*)&write_lock, 0);
     227            else if (read_waiter_count > 0)
     228                _kern_mutex_unlock((int32*)&read_lock, B_USER_MUTEX_UNBLOCK_ALL);
     229        }
    174230
    175231        return B_OK;
    176232    }
    177233
    178234private:
    179     status_t _Wait(bool writer, bigtime_t timeout)
    180     {
    181         if (timeout == 0)
    182             return B_TIMED_OUT;
    183 
    184         Waiter waiter(writer);
    185         waiters.Add(&waiter);
    186         waiter.queued = true;
    187         waiter.userThread->wait_status = 1;
    188 
    189         if (writer)
    190             writer_count++;
    191 
    192         StructureUnlock();
    193         status_t error = _kern_block_thread(
    194             timeout >= 0 ? B_ABSOLUTE_REAL_TIME_TIMEOUT : 0, timeout);
    195         StructureLock();
    196 
    197         if (!waiter.queued)
    198             return waiter.status;
    199 
    200         // we're still queued, which means an error (timeout, interrupt)
    201         // occurred
    202         waiters.Remove(&waiter);
    203 
    204         if (writer)
    205             writer_count--;
    206 
    207         _Unblock();
    208 
    209         return error;
    210     }
    211 
    212     void _Unblock()
    213     {
    214         // Check whether there any waiting threads at all and whether anyone
    215         // has the write lock
    216         Waiter* waiter = waiters.Head();
    217         if (waiter == NULL || owner >= 0)
    218             return;
    219 
    220         // writer at head of queue?
    221         if (waiter->writer) {
    222             if (reader_count == 0) {
    223                 waiter->status = B_OK;
    224                 waiter->queued = false;
    225                 waiters.Remove(waiter);
    226                 owner = waiter->thread;
    227 
    228                 if (waiter->userThread->wait_status > 0)
    229                     _kern_unblock_thread(waiter->thread, B_OK);
    230             }
    231             return;
    232         }
    233 
    234         // wake up one or more readers -- we unblock more than one reader at
    235         // a time to save trips to the kernel
    236         while (!waiters.IsEmpty() && !waiters.Head()->writer) {
    237             static const int kMaxReaderUnblockCount = 128;
    238             thread_id readers[kMaxReaderUnblockCount];
    239             int readerCount = 0;
    240 
    241             while (readerCount < kMaxReaderUnblockCount
    242                     && (waiter = waiters.Head()) != NULL
    243                     && !waiter->writer) {
    244                 waiter->status = B_OK;
    245                 waiter->queued = false;
    246                 waiters.Remove(waiter);
    247 
    248                 if (waiter->userThread->wait_status > 0) {
    249                     readers[readerCount++] = waiter->thread;
    250                     reader_count++;
    251                 }
    252             }
    253 
    254             if (readerCount > 0)
    255                 _kern_unblock_threads(readers, readerCount, B_OK);
    256         }
    257     }
    258 
    259235
    260236    struct Locking {
    261237        inline bool Lock(LocalRWLock* lockable)