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 <hippo@be.com>
19 */
20
21#include "apr_arch_proc_mutex.h"
22#include "apr_strings.h"
23#include "apr_portable.h"
24
25static apr_status_t _proc_mutex_cleanup(void * data)
26{
27    apr_proc_mutex_t *lock = (apr_proc_mutex_t*)data;
28    if (lock->LockCount != 0) {
29        /* we're still locked... */
30    	while (atomic_add(&lock->LockCount , -1) > 1){
31    	    /* OK we had more than one person waiting on the lock so
32    	     * the sem is also locked. Release it until we have no more
33    	     * locks left.
34    	     */
35            release_sem (lock->Lock);
36    	}
37    }
38    delete_sem(lock->Lock);
39    return APR_SUCCESS;
40}
41
42APR_DECLARE(apr_status_t) apr_proc_mutex_create(apr_proc_mutex_t **mutex,
43                                                const char *fname,
44                                                apr_lockmech_e mech,
45                                                apr_pool_t *pool)
46{
47    apr_proc_mutex_t *new;
48    apr_status_t stat = APR_SUCCESS;
49
50    if (mech != APR_LOCK_DEFAULT) {
51        return APR_ENOTIMPL;
52    }
53
54    new = (apr_proc_mutex_t *)apr_pcalloc(pool, sizeof(apr_proc_mutex_t));
55    if (new == NULL){
56        return APR_ENOMEM;
57    }
58
59    if ((stat = create_sem(0, "APR_Lock")) < B_NO_ERROR) {
60        _proc_mutex_cleanup(new);
61        return stat;
62    }
63    new->LockCount = 0;
64    new->Lock = stat;
65    new->pool  = pool;
66
67    apr_pool_cleanup_register(new->pool, (void *)new, _proc_mutex_cleanup,
68                              apr_pool_cleanup_null);
69
70    (*mutex) = new;
71    return APR_SUCCESS;
72}
73
74APR_DECLARE(apr_status_t) apr_proc_mutex_child_init(apr_proc_mutex_t **mutex,
75                                                    const char *fname,
76                                                    apr_pool_t *pool)
77{
78    return APR_SUCCESS;
79}
80
81APR_DECLARE(apr_status_t) apr_proc_mutex_lock(apr_proc_mutex_t *mutex)
82{
83    int32 stat;
84
85	if (atomic_add(&mutex->LockCount, 1) > 0) {
86		if ((stat = acquire_sem(mutex->Lock)) < B_NO_ERROR) {
87		    atomic_add(&mutex->LockCount, -1);
88		    return stat;
89		}
90	}
91    return APR_SUCCESS;
92}
93
94APR_DECLARE(apr_status_t) apr_proc_mutex_trylock(apr_proc_mutex_t *mutex)
95{
96    return APR_ENOTIMPL;
97}
98
99APR_DECLARE(apr_status_t) apr_proc_mutex_unlock(apr_proc_mutex_t *mutex)
100{
101    int32 stat;
102
103	if (atomic_add(&mutex->LockCount, -1) > 1) {
104        if ((stat = release_sem(mutex->Lock)) < B_NO_ERROR) {
105            atomic_add(&mutex->LockCount, 1);
106            return stat;
107        }
108    }
109    return APR_SUCCESS;
110}
111
112APR_DECLARE(apr_status_t) apr_proc_mutex_destroy(apr_proc_mutex_t *mutex)
113{
114    apr_status_t stat;
115    if ((stat = _proc_mutex_cleanup(mutex)) == APR_SUCCESS) {
116        apr_pool_cleanup_kill(mutex->pool, mutex, _proc_mutex_cleanup);
117        return APR_SUCCESS;
118    }
119    return stat;
120}
121
122APR_DECLARE(apr_status_t) apr_proc_mutex_cleanup(void *mutex)
123{
124    return _proc_mutex_cleanup(mutex);
125}
126
127
128APR_DECLARE(const char *) apr_proc_mutex_lockfile(apr_proc_mutex_t *mutex)
129{
130    return NULL;
131}
132
133APR_DECLARE(const char *) apr_proc_mutex_name(apr_proc_mutex_t *mutex)
134{
135    return "beossem";
136}
137
138APR_DECLARE(const char *) apr_proc_mutex_defname(void)
139{
140    return "beossem";
141}
142
143APR_POOL_IMPLEMENT_ACCESSOR(proc_mutex)
144
145/* Implement OS-specific accessors defined in apr_portable.h */
146
147APR_DECLARE(apr_status_t) apr_os_proc_mutex_get(apr_os_proc_mutex_t *ospmutex,
148                                                apr_proc_mutex_t *pmutex)
149{
150    ospmutex->sem = pmutex->Lock;
151    ospmutex->ben = pmutex->LockCount;
152    return APR_SUCCESS;
153}
154
155APR_DECLARE(apr_status_t) apr_os_proc_mutex_put(apr_proc_mutex_t **pmutex,
156                                                apr_os_proc_mutex_t *ospmutex,
157                                                apr_pool_t *pool)
158{
159    if (pool == NULL) {
160        return APR_ENOPOOL;
161    }
162    if ((*pmutex) == NULL) {
163        (*pmutex) = (apr_proc_mutex_t *)apr_pcalloc(pool, sizeof(apr_proc_mutex_t));
164        (*pmutex)->pool = pool;
165    }
166    (*pmutex)->Lock = ospmutex->sem;
167    (*pmutex)->LockCount = ospmutex->ben;
168    return APR_SUCCESS;
169}
170
171