4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
35 * Access control structure for a piece of nscd data. This structure
36 * is always tagged before the nscd data. nscd_alloc, which should
37 * be used to allocate memory that requires access control or usage
38 * count control, will initialize this access control structure at the
39 * start of the memory returned to the caller.
41 struct nscd_access_s
{
42 void *data
; /* addr of real data */
43 void (*free_func
)(nscd_acc_data_t
*data
); /* destructor */
44 mutex_t mutex
; /* protect this structure */
46 rwlock_t
*data_rwlock
;
48 int nUse
; /* usage count */
50 int delete; /* no longer available */
51 nscd_seq_num_t seq_num
; /* sequence number */
54 /* size should be in multiple of 8 */
55 static int sizeof_access
= roundup(sizeof (nscd_access_t
));
57 #define ABORT_DUE_TO_NO_VALID_NSCD_ACCESS_DATA 0
58 #define ASSERT_ACCESS_DATA \
59 if (access->data != data) \
60 assert(ABORT_DUE_TO_NO_VALID_NSCD_ACCESS_DATA)
62 #define SET_ACCESS_PTR \
63 access = (nscd_access_t *) \
64 ((void *)((char *)data - sizeof_access))
66 static void _nscd_free(nscd_acc_data_t
*data
);
69 * FUNCTION: _nscd_release
71 * Decrements the usage count maintained in the access data
72 * tagged before 'data'. Delete the nscd data item if the delete
73 * flag is set and the usage count reaches 0.
77 nscd_acc_data_t
*data
)
79 nscd_access_t
*access
;
80 char *me
= "_nscd_release";
87 _NSCD_LOG(NSCD_LOG_ACCESS_INFO
, NSCD_LOG_LEVEL_DEBUG
)
88 (me
, "data = %p, access->data = %p, "
89 "seq = %lld, nUse = %d\n",
90 data
, access
->data
, access
->seq_num
, access
->nUse
);
93 (void) mutex_lock(&access
->mutex
);
95 if (access
->nUse
< 0) {
96 #define ACCESS_NUSE_LESS_THAN_ZERO 0
97 assert(ACCESS_NUSE_LESS_THAN_ZERO
);
99 if (access
->nUse
<= 0 &&
100 access
->delete == 1) {
102 _NSCD_LOG(NSCD_LOG_ACCESS_INFO
, NSCD_LOG_LEVEL_DEBUG
)
103 (me
, "deleting data %p\n", access
->data
);
104 (access
->free_func
)(access
->data
);
107 * if we get here, no other thread could be
108 * holding the access->mutex lock, It is safe
109 * to free the memory containing the mutex
110 * structure. No mutex_unlock is necessary.
114 (void) mutex_unlock(&access
->mutex
);
119 * FUNCTION: _nscd_destroy
121 * Marks the nscd data item as to-be-deleted and then releases
122 * (If the usage count happens to be zero, then _nscd_release()
123 * will destroy the data.)
125 * Note that _nscd_destroy should only be called if the
126 * caller has created the nscd data with _nscd_alloc
127 * (with the exception of _nscd_set). That nscd data
128 * item should be private to the caller.
132 nscd_acc_data_t
*data
)
134 nscd_access_t
*access
;
135 char *me
= "_nscd_destroy";
142 _NSCD_LOG(NSCD_LOG_ACCESS_INFO
, NSCD_LOG_LEVEL_DEBUG
)
143 (me
, "data = %p, access->data = %p\n", data
, access
->data
);
146 (void) mutex_lock(&access
->mutex
);
148 (void) mutex_unlock(&access
->mutex
);
154 * FUNCTION: _nscd_get
156 * Increment the usage count by one if 'data' can
157 * be found in the internal address database.
161 nscd_acc_data_t
*data
)
163 nscd_access_t
*access
;
165 rwlock_t
*addr_rwlock
;
166 char *me
= "_nscd_get";
173 _NSCD_LOG(NSCD_LOG_ACCESS_INFO
, NSCD_LOG_LEVEL_DEBUG
)
174 (me
, "data = %p, access->data = %p, seq#= %lld, nUse = %d\n",
175 data
, access
->data
, access
->seq_num
, access
->nUse
);
179 * see if this addr is still valid,
180 * if so, _nscd_is_int_addr will
181 * do a read lock on the returned
182 * multiple readers/single writer lock
183 * to prevent the access data from being
184 * deleted while it is being accessed.
186 if ((addr_rwlock
= _nscd_is_int_addr(data
,
187 access
->seq_num
)) == NULL
) {
188 _NSCD_LOG(NSCD_LOG_ACCESS_INFO
, NSCD_LOG_LEVEL_DEBUG
)
189 (me
, "internal address %p not found\n", data
);
190 assert(addr_rwlock
!= NULL
);
194 (void) mutex_lock(&access
->mutex
);
195 if (access
->delete == 1)
199 (void) mutex_unlock(&access
->mutex
);
202 * done with the multiple readers/single writer lock
204 (void) rw_unlock(addr_rwlock
);
210 * FUNCTION: _nscd_set
212 * _nscd_set sets the address of a nscd data item
213 * to 'new' and delete the old nscd data (old).
214 * The pointer 'new' is returned.
218 nscd_acc_data_t
*old
,
219 nscd_acc_data_t
*new)
221 nscd_acc_data_t
*old_data
, *new_data
;
222 char *me
= "_nscd_set";
227 _NSCD_LOG(NSCD_LOG_ACCESS_INFO
, NSCD_LOG_LEVEL_DEBUG
)
228 (me
, "new = %p, old = %p\n", new, old
);
230 old_data
= _nscd_get(old
);
231 new_data
= _nscd_get(new);
233 if (old_data
!= new_data
) {
235 _nscd_destroy(old_data
);
236 _nscd_release(new_data
);
240 /* if old_data == new_data, both must be NULL */
245 * FUNCTION: _nscd_rdlock
247 * Lock (rw_rdlock) a nscd data item for reading. The caller
248 * needs to call _nscd_rw_unlock() to unlock the data item
249 * when done using the data.
253 nscd_acc_data_t
*data
)
255 nscd_access_t
*access
;
257 char *me
= "_nscd_rdlock";
259 ret
= _nscd_get(data
);
266 _NSCD_LOG(NSCD_LOG_ACCESS_INFO
, NSCD_LOG_LEVEL_DEBUG
)
267 (me
, "data = %p, access->data = %p\n", data
, access
->data
);
270 assert(access
->data_rwlock
!= NULL
);
272 (void) rw_rdlock(access
->data_rwlock
);
278 * FUNCTION: _nscd_wrlock
280 * Lock (rw_wrlock) a nscd data item for writing. The caller
281 * needs to call _nscd_rw_unlock() to unlock the data item
282 * when done using the data.
286 nscd_acc_data_t
*data
)
288 nscd_access_t
*access
;
290 char *me
= "_nscd_wrlock";
292 ret
= _nscd_get(data
);
299 _NSCD_LOG(NSCD_LOG_ACCESS_INFO
, NSCD_LOG_LEVEL_DEBUG
)
300 (me
, "data = %p, access->data = %p\n", data
, access
->data
);
303 assert(access
->data_rwlock
!= NULL
);
305 (void) rw_wrlock(access
->data_rwlock
);
311 * FUNCTION: _nscd_rw_unlock
313 * Unlock (rw_unlock) a locked nscd data item.
317 nscd_acc_data_t
*data
)
319 nscd_access_t
*access
;
320 char *me
= "_nscd_rw_unlock";
327 _NSCD_LOG(NSCD_LOG_ACCESS_INFO
, NSCD_LOG_LEVEL_DEBUG
)
328 (me
, "data = %p, access->data = %p\n",
332 assert(access
->data_rwlock
!= NULL
);
334 (void) rw_unlock(access
->data_rwlock
);
339 * FUNCTION: _nscd_rw_unlock_no_release
341 * Unlock (rw_unlock) a locked nscd data item but without release
342 * it, i.e., without decrement the usage count to indicate that
343 * the data item is still being referenced.
346 _nscd_rw_unlock_no_release(
347 nscd_acc_data_t
*data
)
349 nscd_access_t
*access
;
357 assert(access
->data_rwlock
!= NULL
);
359 (void) rw_unlock(access
->data_rwlock
);
363 * FUNCTION: _nscd_mutex_lock
365 * Lock (mutex_lock) a nscd data item. The caller needs
366 * to call _nscd_mutex_unlock() to unlock the data item
367 * when done using the data.
371 nscd_acc_data_t
*data
)
373 nscd_access_t
*access
;
375 char *me
= "_nscd_mutex_lock";
377 ret
= _nscd_get(data
);
384 _NSCD_LOG(NSCD_LOG_ACCESS_INFO
, NSCD_LOG_LEVEL_DEBUG
)
385 (me
, "data = %p, access->data = %p\n", data
, access
->data
);
388 assert(access
->data_mutex
!= NULL
);
390 (void) mutex_lock(access
->data_mutex
);
397 * FUNCTION: _nscd_mutex_unlock
399 * Unlock a locked nscd data item (that were locked by _nscd_mutex_lock)..
403 nscd_acc_data_t
*data
)
405 nscd_access_t
*access
;
406 char *me
= "_nscd_mutex_unlock";
413 _NSCD_LOG(NSCD_LOG_ACCESS_INFO
, NSCD_LOG_LEVEL_DEBUG
)
414 (me
, "data = %p, access->data = %p\n", data
, access
->data
);
417 assert(access
->data_mutex
!= NULL
);
419 (void) mutex_unlock(access
->data_mutex
);
424 * FUNCTION: _nscd_cond_wait
426 * Perform a condition wait with the cond_t and mutex_t associated
431 nscd_acc_data_t
*data
, cond_t
*cond
)
433 nscd_access_t
*access
;
434 char *me
= "_nscd_cond_wait";
441 _NSCD_LOG(NSCD_LOG_ACCESS_INFO
, NSCD_LOG_LEVEL_DEBUG
)
442 (me
, "data = %p, access->data = %p\n", data
, access
->data
);
445 assert(access
->data_cond
!= NULL
&& access
->data_mutex
!= NULL
);
448 (void) cond_wait(access
->data_cond
, access
->data_mutex
);
450 (void) cond_wait(cond
, access
->data_mutex
);
454 * FUNCTION: _nscd_cond_signal
456 * Perform a condition signal with the cond_t associated with 'data'.
460 nscd_acc_data_t
*data
)
462 nscd_access_t
*access
;
463 char *me
= "_nscd_cond_signal";
470 _NSCD_LOG(NSCD_LOG_ACCESS_INFO
, NSCD_LOG_LEVEL_DEBUG
)
471 (me
, "data = %p, access->data = %p\n", data
, access
->data
);
474 assert(access
->data_cond
!= NULL
);
476 (void) cond_signal(access
->data_cond
);
480 * FUNCTION: _nscd_alloc
482 * Allocate a piece of nscd memory. 'data_free'
483 * is the function to invoke to free the data
484 * stored in this memory, i.e., the desctrctor.
485 * 'option' indicate whether a mutex or a
486 * readers/writer (or both, or none) should also
493 void (*data_free
)(nscd_acc_data_t
*data
),
496 nscd_access_t
*access
;
497 nscd_acc_data_t
*ptr
;
498 nscd_seq_num_t seq_num
;
499 rwlock_t
*rwlock
= NULL
;
500 mutex_t
*mutex
= NULL
;
503 if ((ptr
= (nscd_acc_data_t
*)calloc(1,
504 size
+ sizeof_access
)) == NULL
)
506 if (option
& NSCD_ALLOC_MUTEX
) {
507 if ((mutex
= (mutex_t
*)calloc(1, sizeof (mutex_t
))) ==
512 (void) mutex_init(mutex
, USYNC_THREAD
, NULL
);
514 if (option
& NSCD_ALLOC_RWLOCK
) {
515 if ((rwlock
= (rwlock_t
*)calloc(1, sizeof (rwlock_t
))) ==
521 (void) rwlock_init(rwlock
, USYNC_THREAD
, NULL
);
523 if (option
& NSCD_ALLOC_COND
) {
524 if ((cond
= (cond_t
*)calloc(1, sizeof (cond_t
))) ==
531 (void) cond_init(cond
, USYNC_THREAD
, NULL
);
534 /* get current sequence number */
535 seq_num
= _nscd_get_seq_num();
537 access
= (nscd_access_t
*)ptr
;
538 access
->data
= (char *)ptr
+ sizeof_access
;
539 access
->data_mutex
= mutex
;
540 access
->data_rwlock
= rwlock
;
541 access
->data_cond
= cond
;
545 access
->free_func
= data_free
;
546 access
->seq_num
= seq_num
;
548 /* add the address to the internal address database */
549 if (_nscd_add_int_addr(access
->data
, type
,
550 seq_num
) != NSCD_SUCCESS
) {
555 return (access
->data
);
559 * FUNCTION: _nscd_free
561 * Free a piece of nscd memory.
565 nscd_acc_data_t
*data
)
567 nscd_access_t
*access
;
575 /* remove the address from the internal address database */
576 _nscd_del_int_addr(access
->data
, access
->seq_num
);
578 if (access
->data_mutex
)
579 free(access
->data_mutex
);
580 if (access
->data_rwlock
)
581 free(access
->data_rwlock
);
582 if (access
->data_cond
)
583 free(access
->data_cond
);
585 (void) memset(access
, 0, sizeof (*access
));