summaryrefslogtreecommitdiff
path: root/src/unstable/readwritemutex.cpp
blob: 651a343eaa86405fe1f4963e9825f5ad4ac0d12d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/*
 * Copyright (C) 2007-2014 Xagasoft, All rights reserved.
 *
 * This file is part of the libbu++ library and is released under the
 * terms of the license contained in the file LICENSE.
 */
#include "bu/readwritemutex.h"

Bu::ReadWriteMutex::ReadWriteMutex() :
    iCounter( 0 ),
    bWantWrite( false )
{
}

Bu::ReadWriteMutex::~ReadWriteMutex()
{
}

void Bu::ReadWriteMutex::lockRead()
{
    // Check to see if someone wants to write
    cWrite.lock();
    if( bWantWrite )
    {
        // If so, wait patiently for them to finish
        cWrite.wait();
    }
    cWrite.unlock();

    //  Now lock the read counter
    mRead.lock();
    iCounter++;
    // If the lock counter is one, we just locked for the first time,
    // so we lock the writer.
    if( iCounter == 1 )
        mWrite.lock();
    mRead.unlock();
}

void Bu::ReadWriteMutex::unlockRead()
{
    // Lock the read counter
    mRead.lock();
    iCounter--;
    // If we just decremented the counter back to zero then we can
    // release the write lock
    if( iCounter == 0 )
        mWrite.unlock();
    mRead.unlock();
}

//
// The bWantWrite could be a counter like the read lock counter, however
// once a write lock occurs and bWantWrite is set at least one wite
// will definately occur.  In practice most writes all happen one after
// the other anyway and this way reads get a chance to mingle in.
//
// Really, just getting all currint reads to stop so a write can happen
// I think is sufficient right now.
//
void Bu::ReadWriteMutex::lockWrite()
{
    // Lock the read counter
    mRead.lock();
    if( iCounter > 0 )
    {
        // If there is an active read in progress then we set the bWantWrite
        // flag to make sure no more readers start working.
        cWrite.lock();
        bWantWrite = true;
        cWrite.unlock();
    }
    mRead.unlock();

    // Lock the write lock
    mWrite.lock();
}

void Bu::ReadWriteMutex::unlockWrite()
{
    // Just always set the bWantWrite flag to false at this point, as long
    // as we're locked.
    cWrite.lock();
    bWantWrite = false;
    cWrite.unlock();

    // Release all waiting readers, they won't actually do much until we
    // unlock the write lock though
    cWrite.broadcast();

    // Unlock the write lock
    mWrite.unlock();
}