aboutsummaryrefslogtreecommitdiff
path: root/lib/System/RWMutex.cpp
blob: 5faf220eb91688c7510d4b60fa06edebb098c718 (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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
//===- RWMutex.cpp - Reader/Writer Mutual Exclusion Lock --------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the llvm::sys::RWMutex class.
//
//===----------------------------------------------------------------------===//

#include "llvm/Config/config.h"
#include "llvm/System/RWMutex.h"
#include <cstring>

//===----------------------------------------------------------------------===//
//=== WARNING: Implementation here must contain only TRULY operating system
//===          independent code.
//===----------------------------------------------------------------------===//

#if !defined(ENABLE_THREADS) || ENABLE_THREADS == 0
// Define all methods as no-ops if threading is explicitly disabled
namespace llvm {
using namespace sys;
RWMutexImpl::RWMutexImpl() { }
RWMutexImpl::~RWMutexImpl() { }
bool RWMutexImpl::reader_acquire() { return true; }
bool RWMutexImpl::reader_release() { return true; }
bool RWMutexImpl::writer_acquire() { return true; }
bool RWMutexImpl::writer_release() { return true; }
}
#else

#if defined(HAVE_PTHREAD_H) && defined(HAVE_PTHREAD_RWLOCK_INIT)

#include <cassert>
#include <pthread.h>
#include <stdlib.h>

namespace llvm {
using namespace sys;


// This variable is useful for situations where the pthread library has been
// compiled with weak linkage for its interface symbols. This allows the
// threading support to be turned off by simply not linking against -lpthread.
// In that situation, the value of pthread_mutex_init will be 0 and
// consequently pthread_enabled will be false. In such situations, all the
// pthread operations become no-ops and the functions all return false. If
// pthread_rwlock_init does have an address, then rwlock support is enabled.
// Note: all LLVM tools will link against -lpthread if its available since it
//       is configured into the LIBS variable.
// Note: this line of code generates a warning if pthread_rwlock_init is not
//       declared with weak linkage. It's safe to ignore the warning.
static const bool pthread_enabled = true;

// Construct a RWMutex using pthread calls
RWMutexImpl::RWMutexImpl()
  : data_(0)
{
  if (pthread_enabled)
  {
    // Declare the pthread_rwlock data structures
    pthread_rwlock_t* rwlock =
      static_cast<pthread_rwlock_t*>(malloc(sizeof(pthread_rwlock_t)));

#ifdef __APPLE__
    // Workaround a bug/mis-feature in Darwin's pthread_rwlock_init.
    bzero(rwlock, sizeof(pthread_rwlock_t));
#endif

    pthread_rwlockattr_t attr;

    // Initialize the rwlock attributes
    int errorcode = pthread_rwlockattr_init(&attr);
    assert(errorcode == 0);

#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__DragonFly__)
    // Make it a process local rwlock
    errorcode = pthread_rwlockattr_setpshared(&attr, PTHREAD_PROCESS_PRIVATE);
#endif

    // Initialize the rwlock
    errorcode = pthread_rwlock_init(rwlock, &attr);
    assert(errorcode == 0);

    // Destroy the attributes
    errorcode = pthread_rwlockattr_destroy(&attr);
    assert(errorcode == 0);

    // Assign the data member
    data_ = rwlock;
  }
}

// Destruct a RWMutex
RWMutexImpl::~RWMutexImpl()
{
  if (pthread_enabled)
  {
    pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_);
    assert(rwlock != 0);
    pthread_rwlock_destroy(rwlock);
    free(rwlock);
  }
}

bool
RWMutexImpl::reader_acquire()
{
  if (pthread_enabled)
  {
    pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_);
    assert(rwlock != 0);

    int errorcode = pthread_rwlock_rdlock(rwlock);
    return errorcode == 0;
  } else return false;
}

bool
RWMutexImpl::reader_release()
{
  if (pthread_enabled)
  {
    pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_);
    assert(rwlock != 0);

    int errorcode = pthread_rwlock_unlock(rwlock);
    return errorcode == 0;
  } else return false;
}

bool
RWMutexImpl::writer_acquire()
{
  if (pthread_enabled)
  {
    pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_);
    assert(rwlock != 0);

    int errorcode = pthread_rwlock_wrlock(rwlock);
    return errorcode == 0;
  } else return false;
}

bool
RWMutexImpl::writer_release()
{
  if (pthread_enabled)
  {
    pthread_rwlock_t* rwlock = static_cast<pthread_rwlock_t*>(data_);
    assert(rwlock != 0);

    int errorcode = pthread_rwlock_unlock(rwlock);
    return errorcode == 0;
  } else return false;
}

}

#elif defined(LLVM_ON_UNIX)
#include "Unix/RWMutex.inc"
#elif defined( LLVM_ON_WIN32)
#include "Win32/RWMutex.inc"
#else
#warning Neither LLVM_ON_UNIX nor LLVM_ON_WIN32 was set in System/Mutex.cpp
#endif
#endif