Apache HTTPD
thread_rwlock.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*Read/Write locking implementation based on the MultiLock code from
18 * Stephen Beaulieu <[email protected]>
19 */
20
21#include "apr_arch_thread_rwlock.h"
22#include "apr_strings.h"
23#include "apr_portable.h"
24
25#define BIG_NUM 100000
26
28{
30
31 if (mutex->ReadCount != 0) {
32 while (atomic_add(&mutex->ReadCount , -1) > 1){
33 release_sem (mutex->Read);
34 }
35 }
36 if (mutex->WriteCount != 0) {
37 while (atomic_add(&mutex->WriteCount , -1) > 1){
38 release_sem (mutex->Write);
39 }
40 }
41 if (mutex->LockCount != 0) {
42 while (atomic_add(&mutex->LockCount , -1) > 1){
43 release_sem (mutex->Lock);
44 }
45 }
46
47 delete_sem(mutex->Read);
48 delete_sem(mutex->Write);
49 delete_sem(mutex->Lock);
50 return APR_SUCCESS;
51}
52
55{
57
59 if (new == NULL){
60 return APR_ENOMEM;
61 }
62
63 new->pool = pool;
64 /* we need to make 3 locks... */
65 new->ReadCount = 0;
66 new->WriteCount = 0;
67 new->LockCount = 0;
68 new->Read = create_sem(0, "APR_ReadLock");
69 new->Write = create_sem(0, "APR_WriteLock");
70 new->Lock = create_sem(0, "APR_Lock");
71
72 if (new->Lock < 0 || new->Read < 0 || new->Write < 0) {
74 return -1;
75 }
76
79 (*rwlock) = new;
80 return APR_SUCCESS;
81}
82
84{
85 int32 rv = APR_SUCCESS;
86
87 if (find_thread(NULL) == rwlock->writer) {
88 /* we're the writer - no problem */
89 rwlock->Nested++;
90 } else {
91 /* we're not the writer */
92 int32 r = atomic_add(&rwlock->ReadCount, 1);
93 if (r < 0) {
94 /* Oh dear, writer holds lock, wait for sem */
97 }
98 }
99
100 return rv;
101}
102
104{
105 return APR_ENOTIMPL;
106}
107
109{
110 int rv = APR_SUCCESS;
111
112 if (find_thread(NULL) == rwlock->writer) {
113 rwlock->Nested++;
114 } else {
115 /* we're not the writer... */
116 if (atomic_add(&rwlock->LockCount, 1) >= 1) {
117 /* we're locked - acquire the sem */
120 }
121 if (rv == APR_SUCCESS) {
122 /* decrement the ReadCount to a large -ve number so that
123 * we block on new readers...
124 */
125 int32 readers = atomic_add(&rwlock->ReadCount, -BIG_NUM);
126 if (readers > 0) {
127 /* readers are holding the lock */
128 rv = acquire_sem_etc(rwlock->Write, readers, B_DO_NOT_RESCHEDULE,
130 }
131 if (rv == APR_SUCCESS)
132 rwlock->writer = find_thread(NULL);
133 }
134 }
135
136 return rv;
137}
138
140{
141 return APR_ENOTIMPL;
142}
143
145{
147 int32 readers;
148
149 /* we know we hold the lock, so don't check it :) */
150 if (find_thread(NULL) == rwlock->writer) {
151 /* we know we hold the lock, so don't check it :) */
152 if (rwlock->Nested > 1) {
153 /* we're recursively locked */
154 rwlock->Nested--;
155 return APR_SUCCESS;
156 }
157 /* OK so we need to release the sem if we have it :) */
158 readers = atomic_add(&rwlock->ReadCount, BIG_NUM) + BIG_NUM;
159 if (readers > 0) {
160 rv = release_sem_etc(rwlock->Read, readers, B_DO_NOT_RESCHEDULE);
161 }
162 if (rv == APR_SUCCESS) {
163 rwlock->writer = -1;
164 if (atomic_add(&rwlock->LockCount, -1) > 1) {
165 rv = release_sem_etc(rwlock->Lock, 1, B_DO_NOT_RESCHEDULE);
166 }
167 }
168 } else {
169 /* We weren't the Writer, so just release the ReadCount... */
170 if (atomic_add(&rwlock->ReadCount, -1) < 0) {
171 /* we have a writer waiting for the lock, so release it */
172 rv = release_sem_etc(rwlock->Write, 1, B_DO_NOT_RESCHEDULE);
173 }
174 }
175
176 return rv;
177}
178
180{
182 if ((stat = _thread_rw_cleanup(rwlock)) == APR_SUCCESS) {
184 return APR_SUCCESS;
185 }
186 return stat;
187}
188
190
APR Portability Routines.
APR Strings library.
#define BIG_NUM
static apr_status_t _thread_rw_cleanup(void *data)
request_rec * r
#define APR_ENOMEM
Definition apr_errno.h:683
#define APR_ENOTIMPL
Definition apr_errno.h:476
const void apr_status_t(*) apr_status_t(* APR_DECLARE)(void) apr_pool_pre_cleanup_register(apr_pool_t *p
Definition apr_pools.h:646
apr_size_t size
const char int apr_pool_t * pool
Definition apr_cstr.h:84
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
void * data
#define APR_POOL_IMPLEMENT_ACCESSOR(type)
Definition apr_pools.h:91
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
return NULL
Definition mod_so.c:359
apr_thread_rwlock_tryrdlock(apr_thread_rwlock_t *rwlock)