| /** @file |
| |
| A brief file description |
| |
| @section license License |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| #include "ink_config.h" |
| #include "ink_rwlock.h" |
| |
| //------------------------------------------------------------------------- |
| // ink_rwlock_init |
| //------------------------------------------------------------------------- |
| |
| int |
| ink_rwlock_init(ink_rwlock * rw) |
| { |
| |
| int result; |
| |
| if ((result = ink_mutex_init(&rw->rw_mutex, NULL)) != 0) |
| goto Lerror; |
| ink_cond_init(&rw->rw_condreaders); |
| ink_cond_init(&rw->rw_condwriters); |
| rw->rw_nwaitreaders = 0; |
| rw->rw_nwaitwriters = 0; |
| rw->rw_refcount = 0; |
| rw->rw_magic = RW_MAGIC; |
| |
| return (0); |
| |
| Lerror: |
| return (result); /* an errno value */ |
| |
| } |
| |
| //------------------------------------------------------------------------- |
| // ink_rwlock_destroy |
| //------------------------------------------------------------------------- |
| |
| int |
| ink_rwlock_destroy(ink_rwlock * rw) |
| { |
| |
| if (rw->rw_magic != RW_MAGIC) |
| return (EINVAL); |
| if (rw->rw_refcount != 0 || rw->rw_nwaitreaders != 0 || rw->rw_nwaitwriters != 0) |
| return (EBUSY); |
| |
| ink_mutex_destroy(&rw->rw_mutex); |
| ink_cond_destroy(&rw->rw_condreaders); |
| ink_cond_destroy(&rw->rw_condwriters); |
| rw->rw_magic = 0; |
| |
| return (0); |
| } |
| |
| //------------------------------------------------------------------------- |
| // ink_rwlock_rdlock |
| //------------------------------------------------------------------------- |
| |
| int |
| ink_rwlock_rdlock(ink_rwlock * rw) |
| { |
| |
| int result; |
| |
| if (rw->rw_magic != RW_MAGIC) |
| return (EINVAL); |
| |
| if ((result = ink_mutex_acquire(&rw->rw_mutex)) != 0) |
| return (result); |
| |
| /* give preference to waiting writers */ |
| while (rw->rw_refcount < 0 || rw->rw_nwaitwriters > 0) { |
| rw->rw_nwaitreaders++; |
| ink_cond_wait(&rw->rw_condreaders, &rw->rw_mutex); |
| rw->rw_nwaitreaders--; |
| } |
| rw->rw_refcount++; /* another reader has a read lock */ |
| |
| ink_mutex_release(&rw->rw_mutex); |
| |
| return (0); |
| |
| } |
| |
| //------------------------------------------------------------------------- |
| // ink_rwlock_wrlock |
| //------------------------------------------------------------------------- |
| |
| int |
| ink_rwlock_wrlock(ink_rwlock * rw) |
| { |
| |
| int result; |
| |
| if (rw->rw_magic != RW_MAGIC) |
| return (EINVAL); |
| |
| if ((result = ink_mutex_acquire(&rw->rw_mutex)) != 0) |
| return (result); |
| |
| while (rw->rw_refcount != 0) { |
| rw->rw_nwaitwriters++; |
| ink_cond_wait(&rw->rw_condwriters, &rw->rw_mutex); |
| rw->rw_nwaitwriters--; |
| } |
| rw->rw_refcount = -1; |
| |
| ink_mutex_release(&rw->rw_mutex); |
| |
| return (0); |
| |
| } |
| |
| //------------------------------------------------------------------------- |
| // ink_rwlock_unlock |
| //------------------------------------------------------------------------- |
| |
| int |
| ink_rwlock_unlock(ink_rwlock * rw) |
| { |
| |
| int result; |
| |
| if (rw->rw_magic != RW_MAGIC) |
| return (EINVAL); |
| |
| if ((result = ink_mutex_acquire(&rw->rw_mutex)) != 0) |
| return (result); |
| |
| if (rw->rw_refcount > 0) |
| rw->rw_refcount--; /* releasing a reader */ |
| else if (rw->rw_refcount == -1) |
| rw->rw_refcount = 0; /* releasing a reader */ |
| else |
| ink_release_assert("invalid rw_refcount!"); |
| |
| /* give preference to waiting writers over waiting readers */ |
| if (rw->rw_nwaitwriters > 0) { |
| if (rw->rw_refcount == 0) |
| ink_cond_signal(&rw->rw_condwriters); |
| } else if (rw->rw_nwaitreaders > 0) |
| ink_cond_broadcast(&rw->rw_condreaders); |
| |
| ink_mutex_release(&rw->rw_mutex); |
| |
| return (0); |
| |
| } |