#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "nscd_db.h"
#include "nscd_log.h"
struct nscd_access_s {
void *data;
void (*free_func)(nscd_acc_data_t *data);
mutex_t mutex;
mutex_t *data_mutex;
rwlock_t *data_rwlock;
cond_t *data_cond;
int nUse;
int type;
int delete;
nscd_seq_num_t seq_num;
};
static int sizeof_access = roundup(sizeof (nscd_access_t));
#define ABORT_DUE_TO_NO_VALID_NSCD_ACCESS_DATA 0
#define ASSERT_ACCESS_DATA \
if (access->data != data) \
assert(ABORT_DUE_TO_NO_VALID_NSCD_ACCESS_DATA)
#define SET_ACCESS_PTR \
access = (nscd_access_t *) \
((void *)((char *)data - sizeof_access))
static void _nscd_free(nscd_acc_data_t *data);
void
_nscd_release(
nscd_acc_data_t *data)
{
nscd_access_t *access;
char *me = "_nscd_release";
if (data == NULL)
return;
SET_ACCESS_PTR;
_NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG)
(me, "data = %p, access->data = %p, "
"seq = %lld, nUse = %d\n",
data, access->data, access->seq_num, access->nUse);
ASSERT_ACCESS_DATA;
(void) mutex_lock(&access->mutex);
access->nUse--;
if (access->nUse < 0) {
#define ACCESS_NUSE_LESS_THAN_ZERO 0
assert(ACCESS_NUSE_LESS_THAN_ZERO);
}
if (access->nUse <= 0 &&
access->delete == 1) {
_NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG)
(me, "deleting data %p\n", access->data);
(access->free_func)(access->data);
_nscd_free(data);
} else
(void) mutex_unlock(&access->mutex);
}
static void
_nscd_destroy(
nscd_acc_data_t *data)
{
nscd_access_t *access;
char *me = "_nscd_destroy";
if (data == NULL)
return;
SET_ACCESS_PTR;
_NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG)
(me, "data = %p, access->data = %p\n", data, access->data);
ASSERT_ACCESS_DATA;
(void) mutex_lock(&access->mutex);
access->delete = 1;
(void) mutex_unlock(&access->mutex);
_nscd_release(data);
}
nscd_acc_data_t *
_nscd_get(
nscd_acc_data_t *data)
{
nscd_access_t *access;
void *ret = data;
rwlock_t *addr_rwlock;
char *me = "_nscd_get";
if (data == NULL)
return (NULL);
SET_ACCESS_PTR;
_NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG)
(me, "data = %p, access->data = %p, seq#= %lld, nUse = %d\n",
data, access->data, access->seq_num, access->nUse);
ASSERT_ACCESS_DATA;
if ((addr_rwlock = _nscd_is_int_addr(data,
access->seq_num)) == NULL) {
_NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG)
(me, "internal address %p not found\n", data);
assert(addr_rwlock != NULL);
return (NULL);
}
(void) mutex_lock(&access->mutex);
if (access->delete == 1)
ret = NULL;
else
access->nUse++;
(void) mutex_unlock(&access->mutex);
(void) rw_unlock(addr_rwlock);
return (ret);
}
nscd_acc_data_t *
_nscd_set(
nscd_acc_data_t *old,
nscd_acc_data_t *new)
{
nscd_acc_data_t *old_data, *new_data;
char *me = "_nscd_set";
if (new == old)
return (old);
_NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG)
(me, "new = %p, old = %p\n", new, old);
old_data = _nscd_get(old);
new_data = _nscd_get(new);
if (old_data != new_data) {
_nscd_destroy(old_data);
_nscd_release(new_data);
return (new_data);
}
return (NULL);
}
nscd_acc_data_t *
_nscd_rdlock(
nscd_acc_data_t *data)
{
nscd_access_t *access;
void *ret;
char *me = "_nscd_rdlock";
ret = _nscd_get(data);
if (ret == NULL)
return (NULL);
SET_ACCESS_PTR;
_NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG)
(me, "data = %p, access->data = %p\n", data, access->data);
ASSERT_ACCESS_DATA;
assert(access->data_rwlock != NULL);
(void) rw_rdlock(access->data_rwlock);
return (ret);
}
nscd_acc_data_t *
_nscd_wrlock(
nscd_acc_data_t *data)
{
nscd_access_t *access;
void *ret;
char *me = "_nscd_wrlock";
ret = _nscd_get(data);
if (ret == NULL)
return (NULL);
SET_ACCESS_PTR;
_NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG)
(me, "data = %p, access->data = %p\n", data, access->data);
ASSERT_ACCESS_DATA;
assert(access->data_rwlock != NULL);
(void) rw_wrlock(access->data_rwlock);
return (ret);
}
void
_nscd_rw_unlock(
nscd_acc_data_t *data)
{
nscd_access_t *access;
char *me = "_nscd_rw_unlock";
if (data == NULL)
return;
SET_ACCESS_PTR;
_NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG)
(me, "data = %p, access->data = %p\n",
data, access->data);
ASSERT_ACCESS_DATA;
assert(access->data_rwlock != NULL);
(void) rw_unlock(access->data_rwlock);
_nscd_release(data);
}
void
_nscd_rw_unlock_no_release(
nscd_acc_data_t *data)
{
nscd_access_t *access;
if (data == NULL)
return;
SET_ACCESS_PTR;
ASSERT_ACCESS_DATA;
assert(access->data_rwlock != NULL);
(void) rw_unlock(access->data_rwlock);
}
nscd_acc_data_t *
_nscd_mutex_lock(
nscd_acc_data_t *data)
{
nscd_access_t *access;
void *ret;
char *me = "_nscd_mutex_lock";
ret = _nscd_get(data);
if (ret == NULL)
return (NULL);
SET_ACCESS_PTR;
_NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG)
(me, "data = %p, access->data = %p\n", data, access->data);
ASSERT_ACCESS_DATA;
assert(access->data_mutex != NULL);
(void) mutex_lock(access->data_mutex);
return (ret);
}
void
_nscd_mutex_unlock(
nscd_acc_data_t *data)
{
nscd_access_t *access;
char *me = "_nscd_mutex_unlock";
if (data == NULL)
return;
SET_ACCESS_PTR;
_NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG)
(me, "data = %p, access->data = %p\n", data, access->data);
ASSERT_ACCESS_DATA;
assert(access->data_mutex != NULL);
(void) mutex_unlock(access->data_mutex);
_nscd_release(data);
}
void
_nscd_cond_wait(
nscd_acc_data_t *data, cond_t *cond)
{
nscd_access_t *access;
char *me = "_nscd_cond_wait";
if (data == NULL)
return;
SET_ACCESS_PTR;
_NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG)
(me, "data = %p, access->data = %p\n", data, access->data);
ASSERT_ACCESS_DATA;
assert(access->data_cond != NULL && access->data_mutex != NULL);
if (cond == NULL)
(void) cond_wait(access->data_cond, access->data_mutex);
else
(void) cond_wait(cond, access->data_mutex);
}
void
_nscd_cond_signal(
nscd_acc_data_t *data)
{
nscd_access_t *access;
char *me = "_nscd_cond_signal";
if (data == NULL)
return;
SET_ACCESS_PTR;
_NSCD_LOG(NSCD_LOG_ACCESS_INFO, NSCD_LOG_LEVEL_DEBUG)
(me, "data = %p, access->data = %p\n", data, access->data);
ASSERT_ACCESS_DATA;
assert(access->data_cond != NULL);
(void) cond_signal(access->data_cond);
}
nscd_acc_data_t *
_nscd_alloc(
int type,
size_t size,
void (*data_free)(nscd_acc_data_t *data),
int option)
{
nscd_access_t *access;
nscd_acc_data_t *ptr;
nscd_seq_num_t seq_num;
rwlock_t *rwlock = NULL;
mutex_t *mutex = NULL;
cond_t *cond = NULL;
if ((ptr = (nscd_acc_data_t *)calloc(1,
size + sizeof_access)) == NULL)
return (NULL);
if (option & NSCD_ALLOC_MUTEX) {
if ((mutex = (mutex_t *)calloc(1, sizeof (mutex_t))) ==
NULL) {
free(ptr);
return (NULL);
} else
(void) mutex_init(mutex, USYNC_THREAD, NULL);
}
if (option & NSCD_ALLOC_RWLOCK) {
if ((rwlock = (rwlock_t *)calloc(1, sizeof (rwlock_t))) ==
NULL) {
free(ptr);
free(mutex);
return (NULL);
} else
(void) rwlock_init(rwlock, USYNC_THREAD, NULL);
}
if (option & NSCD_ALLOC_COND) {
if ((cond = (cond_t *)calloc(1, sizeof (cond_t))) ==
NULL) {
free(ptr);
free(mutex);
free(rwlock);
return (NULL);
} else
(void) cond_init(cond, USYNC_THREAD, NULL);
}
seq_num = _nscd_get_seq_num();
access = (nscd_access_t *)ptr;
access->data = (char *)ptr + sizeof_access;
access->data_mutex = mutex;
access->data_rwlock = rwlock;
access->data_cond = cond;
access->nUse = 0;
access->delete = 0;
access->type = type;
access->free_func = data_free;
access->seq_num = seq_num;
if (_nscd_add_int_addr(access->data, type,
seq_num) != NSCD_SUCCESS) {
free(ptr);
return (NULL);
}
return (access->data);
}
static void
_nscd_free(
nscd_acc_data_t *data)
{
nscd_access_t *access;
if (data == NULL)
return;
SET_ACCESS_PTR;
ASSERT_ACCESS_DATA;
_nscd_del_int_addr(access->data, access->seq_num);
if (access->data_mutex)
free(access->data_mutex);
if (access->data_rwlock)
free(access->data_rwlock);
if (access->data_cond)
free(access->data_cond);
(void) memset(access, 0, sizeof (*access));
free(access);
}