Ticket #8798: 0001-pthread_rwlock-draft-local-implementation.patch

File 0001-pthread_rwlock-draft-local-implementation.patch, 7.5 KB (added by korli, 7 years ago)

Try at implementing local pthread_rwlock

  • headers/posix/sys/types.h

    From b9dbc7b1f7cf3e6994686701f185daa71cab69bf 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: draft local implementation.
    
    ---
     headers/posix/sys/types.h                          |   9 +-
     .../libroot/posix/pthread/pthread_rwlock.cpp       | 190 +++++++++------------
     2 files changed, 87 insertions(+), 112 deletions(-)
    
    diff --git a/headers/posix/sys/types.h b/headers/posix/sys/types.h
    index b09aba5..745c1fa 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   unused;
     112            __haiku_std_int32   mutex;
    113113            __haiku_std_int32   reader_count;
    114114            __haiku_std_int32   writer_count;
    115             void*               waiters[2];
     115            __haiku_std_int32   write_waiter_count;
     116            __haiku_std_int32   write_lock;
     117            __haiku_std_int32   read_waiter_count;
     118            __haiku_std_int32   read_lock;
    116119        } local;
    117120    } u;
    118121};
  • 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..b8c667c 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     unused;
     98    int32_t     mutex;
    9899    int32_t     reader_count;
    99100    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;
     101    int32_t     write_waiter_count;
     102    int32_t     write_lock;
     103    int32_t     read_waiter_count;
     104    int32_t     read_lock;
    104105
    105106    status_t Init()
    106107    {
    107108        flags = 0;
    108109        owner = -1;
    109         lock_sem = create_sem(0, "pthread rwlock");
    110         lock_count = 1;
     110        mutex = 0;
    111111        reader_count = 0;
    112112        writer_count = 0;
    113         new(&waiters) WaiterList;
    114 
    115         return lock_sem >= 0 ? B_OK : EAGAIN;
     113        write_waiter_count = 0;
     114        write_lock = 0;
     115        read_waiter_count = 0;
     116        read_lock = 0;
     117        return B_OK;
    116118    }
    117119
    118120    status_t Destroy()
    119121    {
    120         if (lock_sem < 0)
    121             return B_BAD_VALUE;
    122         return delete_sem(lock_sem) == B_OK ? B_OK : B_BAD_VALUE;
     122        Locker locker(this);
     123        if (reader_count > 0 || writer_count > 0 || read_waiter_count > 0
     124            || write_waiter_count > 0)
     125            return EBUSY;
     126        return 0;
    123127    }
    124128
    125129    bool StructureLock()
    126130    {
    127         if (atomic_add((int32*)&lock_count, -1) <= 0)
    128             acquire_sem(lock_sem);
     131        // Enter critical region: lock the mutex
     132        int32 status = atomic_or((int32*)&mutex, B_USER_MUTEX_LOCKED);
     133
     134        // If already locked, call the kernel
     135        if (status & (B_USER_MUTEX_LOCKED | B_USER_MUTEX_WAITING)) {
     136            do {
     137                status = _kern_mutex_lock((int32*)&mutex, NULL, 0, 0);
     138            } while (status == B_INTERRUPTED);
     139
     140            if (status != B_OK)
     141                return false;
     142        }
    129143        return true;
    130144    }
    131145
    132146    void StructureUnlock()
    133147    {
    134         if (atomic_add((int32*)&lock_count, 1) < 0)
    135             release_sem(lock_sem);
     148        // Exit critical region: unlock the mutex
     149        int32 status = atomic_and((int32*)&mutex,
     150            ~(int32)B_USER_MUTEX_LOCKED);
     151
     152        if (status & B_USER_MUTEX_WAITING)
     153            _kern_mutex_unlock((int32*)&mutex, 0);
    136154    }
    137155
    138156    status_t ReadLock(bigtime_t timeout)
    139157    {
    140158        Locker locker(this);
    141159
    142         if (writer_count == 0) {
    143             reader_count++;
    144             return B_OK;
     160        status_t status = B_OK;
     161        if (writer_count > 0 || write_waiter_count > 0) {
     162            read_waiter_count++;
     163            do {
     164                atomic_or((int32*)&read_lock, B_USER_MUTEX_LOCKED);
     165                status = _kern_mutex_switch_lock((int32*)&mutex,
     166                    (int32*)&read_lock, "pthread rwlock",
     167                    timeout == B_INFINITE_TIMEOUT ? 0 : B_ABSOLUTE_REAL_TIME_TIMEOUT,
     168                    timeout);
     169                StructureLock();
     170                if (status != 0)
     171                    break;
     172            } while (writer_count > 0 || write_waiter_count > 0);
     173            read_waiter_count--;
    145174        }
    146175
    147         return _Wait(false, timeout);
     176        if (status == 0)
     177            reader_count++;
     178
     179        return status;
    148180    }
    149181
    150182    status_t WriteLock(bigtime_t timeout)
    151183    {
    152184        Locker locker(this);
    153185
    154         if (reader_count == 0 && writer_count == 0) {
     186        status_t status = B_OK;
     187        if (reader_count > 0 || writer_count > 0) {
     188            write_waiter_count++;
     189            do {
     190                atomic_or((int32*)&write_lock, B_USER_MUTEX_LOCKED);
     191                status = _kern_mutex_switch_lock((int32*)&mutex,
     192                    (int32*)&write_lock, "pthread rwlock",
     193                    timeout == B_INFINITE_TIMEOUT ? 0 : B_ABSOLUTE_REAL_TIME_TIMEOUT,
     194                    timeout);
     195                StructureLock();
     196                if (status != 0)
     197                    break;
     198            } while (reader_count > 0 || writer_count > 0);
     199            write_waiter_count--;
     200        }
     201        if (status == 0) {
    155202            writer_count++;
    156203            owner = find_thread(NULL);
    157             return B_OK;
    158204        }
    159 
    160         return _Wait(true, timeout);
     205        return status;
    161206    }
    162207
    163208    status_t Unlock()
    struct LocalRWLock {  
    167212        if (find_thread(NULL) == owner) {
    168213            writer_count--;
    169214            owner = -1;
    170         } else
     215            if (write_waiter_count > 0)
     216                _kern_mutex_unlock((int32*)&write_lock, 0);
     217            else if (read_waiter_count > 0)
     218                _kern_mutex_unlock((int32*)&read_lock, B_USER_MUTEX_UNBLOCK_ALL);
     219        } else {
    171220            reader_count--;
    172 
    173         _Unblock();
     221            if (reader_count == 0 && write_waiter_count > 0)
     222                _kern_mutex_unlock((int32*)&write_lock, 0);
     223            else if (read_waiter_count > 0)
     224                _kern_mutex_unlock((int32*)&read_lock, B_USER_MUTEX_UNBLOCK_ALL);
     225        }
    174226
    175227        return B_OK;
    176228    }
    177229
    178230private:
    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 
    259231
    260232    struct Locking {
    261233        inline bool Lock(LocalRWLock* lockable)