/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <string.h>
#include <pthread.h>
#include <syslog.h>
#include "nis_hashitem.h"
/* We're the magician, so undefine the define-magic */
/*
* The hash table routines below implement nested (or recursive)
* one-writer-or-many-readers locking. The following restrictions
* exist:
*
* Unless an item destructor has been established, an item
* MUST NOT be removed from a list (__nis_pop_item_mt() or
* (__nis_remove_item_mt()) when the thread performing
* the deletion is holding a read-only lock on the item.
* Doing so will result in the thread blocking in
* pthread_cond_wait() waiting for itself to signal on
* the condition variable. Deletion when the invoking
* thread is holding a write lock (any level of nesting),
* or no lock, is OK.
*/
void
void (*itemDestructor)(void *)) {
int errorcode;
if (table != 0) {
if (errorcode != 0) {
"(table->lock) pthread_mutex_init returned %d (%s)",
}
if (errorcode != 0) {
"(table->cond) pthread_cond_init returned %d (%s)",
}
if (errorcode != 0) {
"(table->traverser_id_lock) "
"pthread_mutex_init returned %d (%s)",
}
table->locked_items = 0;
}
}
int
if (table != 0) {
if (traverse) {
/*
* We want exclusive access to everything in the
* table (list). Wait until there are no threads
* either traversing the list, or with exclusive
* access to an item.
*/
table->locked_items != 0) {
"%d: lh table 0x%x trav cond wait",
}
} else {
/*
* Called from the nis_*_item() functions. If no one's
* locked the table, lock it. If the table already is
* being traversed by us, do nothing. Otherwise, wait
* for the lock.
*/
/* Already locked; find out if it's us */
(void) pthread_mutex_lock(
/* It's us. No action. */
dolock = 0;
}
(void) pthread_mutex_unlock(
/* Not us. Wait for the lock */
if (dolock) {
"%d: lh table 0x%x cond wait",
}
}
}
return (1);
} else {
return (0);
}
}
int
int dounlock = 0;
if (table != 0) {
if (traverse) {
/*
* Since we're keeping track of who's traversing the
* table in order to avoid recursive locking in the
* nis_*item() functions, we might as well sanity check
* here.
*/
/*
* Leave traverser_id as it is, so that it
* possible to see which thread last held
* the traverser lock.
*/
dounlock = 1;
/* Wake up other traversers-to-be */
}
} else {
/*
* Called from the nis_*_item() functions. If we're
* traversing the table, leave it locked.
*/
dounlock = 1;
}
}
if (dounlock) {
}
return (1);
} else {
return (0);
}
}
static __nis_hash_item_mt **
int key = 0;
unsigned char *s;
/* Assume table!=0, table lock held */
for (s = (unsigned char *)name; *s != 0; s++) {
key += *s;
}
if (keyp != 0) {
}
break;
}
}
return (pp);
}
/*
* The 'readwrite' argument is interpreted as follows on a successful
* return:
*
* < 0 Exclusive access to item
* 0 Item must not be used or referenced in any way
* > 0 Non-exclusive access (read-only) to item
*
* Except when 'readwrite' == 0, the caller must explicitly release the
* item (__nis_release_item()).
*/
int
int key;
return (0);
return (0);
}
if (readwrite < 0) {
table->locked_items++;
} else if (readwrite > 0) {
table->locked_items++;
}
return (1);
}
void
return;
return;
}
return;
}
}
}
/*
* readwrite: < 0 Exclusive access
* 0 No access; must not use returned item in any way,
* other than to confirm existence indicated by a non-NULL
* return value.
* > 0 Non-exclusive (read-only) access
*
* If trylock != 0 and *trylock != 0 and the item exists but the requested
* lock type cannot be acquired, set *trylock = -1 and return 0.
*/
void *
int *trylock) {
return (0);
/*
* Block waiting for more favorable conditions unless:
*
* The item doesn't exist anymore
*
* 'readwrite' == 0 (verify existence only)
*
* There's a writer, but it's us
*
* There are no writers, and we're satisfied by RO access
*
* A trylock was requested
*/
if (readwrite == 0 ||
break;
break;
break;
*trylock = -1;
return (0);
}
}
if (item != 0) {
if (readwrite < 0) {
table->locked_items++;
}
} else if (readwrite > 0) {
table->locked_items++;
}
}
}
return (item);
}
void *
return (0);
/* Wait until the first item isn't in use by another thread */
mtid = pthread_self();
if (table->destroyItem != 0)
break;
break;
break;
}
/* List might be empty now */
if (item == 0) {
return (0);
}
prev = 0;
if (prev)
else
else
break;
}
}
/*
* We use keychain < 0 to indicate that the item isn't linked
* into the table anymore.
*/
/* Adjust the count of locked items in the table */
if (table->locked_items != 0 &&
table->locked_items--;
if (table->locked_items == 0) {
/* Wake up traversers-to-be */
}
}
/*
* Wake up any threads that were waiting for this item. Obviously,
* such threads must start over scanning the list.
*/
/*
* If the item isn't locked, and an item destructor has been
* established, invoke the destructor.
*/
table->destroyItem != 0) {
item = 0;
} else {
}
/*
* If we get here, and the 'item' is NULL, we've popped the
* item, but also destroyed it. Returning NULL would make
* our caller believe the list is empty, so instead, we invoke
* ourselves to pop the next item.
*/
}
void *
return (0);
/* Find the item, and make sure it's not in use */
mtid = pthread_self();
if (table->destroyItem != 0)
break;
break;
break;
}
if (nl == 0) {
return (0);
}
/* Remove nl from the hash chain */
/* Remove nl from the linked list of all names */
else
/* keychain < 0 means not in table anymore */
/*
* If this item was locked, we can now decrement the count of
* locked items for the table.
*/
if (table->locked_items != 0 &&
table->locked_items--;
if (table->locked_items == 0) {
/* Wake up traversers-to-be */
}
}
/*
* If the item isn't locked, and an item destructor has been
* established, invoke the destructor. In that case, we return
* NULL, so that our caller doesn't try to reference the
* deleted item.
*/
nl = 0;
}
return (nl);
}
/*
* Release an item that had been acquired exclusively or non-exclusively.
* Note that 'readwrite' can assume any integer value, and thus can be
* used to release any level of recursive locking. It's the responsibility
* of the caller to make sure that proper nesting is maintained.
*/
int
int wakeup = 0;
return (0);
/* Caller confused; ignore */
return (0);
}
if (readwrite < 0) {
if (table->locked_items != 0)
table->locked_items--;
wakeup = 1;
}
} else if (readwrite > 0) {
if (table->locked_items != 0)
table->locked_items--;
wakeup = 1;
}
}
if (table->locked_items == 0) {
/* Wake up traversers-to-be */
}
if (wakeup) {
/* Wake up anyone else who wants this item */
}
/*
* Delete if no references, not linked into list, and destructor
* established.
*/
table->destroyItem != 0)
return (1);
}
/*
* Return -1 if item checked out for both reading and writing, 1 if
* readonly, and 0 otherwise.
*/
int
if (item != 0) {
abort();
return (-1);
return (1);
}
}
return (0);
}
/*
* __nis_scan_table_mt()
*
* Iterate over all items in a __nis_hash_table_mt. We ignore
* function should *not* insert or delete items. If the iterator
* function returns TRUE the scan terminates. For compatibility with
* the existing non-MT nis_scan_table() this function has no return
* value.
*/
void
void *funcarg)
{
int slot;
if (table == 0) {
return;
}
return;
}
for (slot = 0;
slot++) {
break;
}
}
}
}