/* * This file is part of QCluster. * * QCluster is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * QCluster is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with QCluster; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Peter Harper * * $Id: locks.c,v 1.1 2003/12/02 06:17:38 rmello Exp $ * * ------------------------------------------------------------------------ * * Manage locks on global data. Maintains a hashtable of object pointers, * which are the keys, and RW locks, which are the values. Functions are * used to get/release access to the objects. These functions use a single RW * lock to make sure access to the locks hashtable is threadsafe. * * This might not be the most efficient mechanism for controlling access to * the global data, but its certainly the cleanest I could find. */ static char rcsid[] = "@(#) $Id: locks.c,v 1.1 2003/12/02 06:17:38 rmello Exp $"; #include "ns.h" #include "locks.h" static Ns_RWLock g_locks_mutex; static Tcl_HashTable g_locks; void q_init_lock (void) { Ns_RWLockInit(&g_locks_mutex); Tcl_InitHashTable(&g_locks, TCL_ONE_WORD_KEYS); } Ns_RWLock * q_add_lock(void *object_ptr) { Tcl_HashEntry *entry; Ns_RWLock *new_lock_ptr; int new_flag; /* * Create the new lock for this object and initialise it. */ new_lock_ptr = ns_malloc(sizeof(Ns_RWLock)); Ns_RWLockInit(new_lock_ptr); /* * Get a write lock on the locks hashtable, and create the lock entry. * Then release the write lock on the locks hashtable. */ Ns_RWLockWrLock(&g_locks_mutex); entry = Tcl_CreateHashEntry(&g_locks, object_ptr, &new_flag); Tcl_SetHashValue(entry, new_lock_ptr); Ns_RWLockUnlock(&g_locks_mutex); return new_lock_ptr; } void q_delete_lock(void *object_ptr) { Tcl_HashEntry *entry; /* * Get a write lock on the locks hashtable, and delete the lock entry. * Then release the write lock on the locks hashtable. */ Ns_RWLockWrLock(&g_locks_mutex); entry = Tcl_FindHashEntry(&g_locks, object_ptr); ns_free(Tcl_GetHashValue(entry)); Tcl_DeleteHashEntry(entry); Ns_RWLockUnlock(&g_locks_mutex); } void q_get_rlock(void *object_ptr) { Tcl_HashEntry *entry; // Ns_Log(Notice,">>>> getting rlock %x",object_ptr); /* * Get a read lock on the locks hashtable, and then get the read lock on * the object lock. * Then release the read lock on the locks hashtable. */ Ns_RWLockRdLock(&g_locks_mutex); entry = Tcl_FindHashEntry(&g_locks, object_ptr); Ns_RWLockRdLock(Tcl_GetHashValue(entry)); Ns_RWLockUnlock(&g_locks_mutex); // Ns_Log(Notice,">>>> got rlock %x",object_ptr); } void q_get_wlock(void *object_ptr) { Tcl_HashEntry *entry; // Ns_Log(Notice,">>>> getting wlock %x",object_ptr); /* * Get a read lock on the locks hashtable, and then get the write lock on * the object lock. * Then release the read lock on the locks hashtable. */ Ns_RWLockRdLock(&g_locks_mutex); entry = Tcl_FindHashEntry(&g_locks, object_ptr); Ns_RWLockWrLock(Tcl_GetHashValue(entry)); Ns_RWLockUnlock(&g_locks_mutex); // Ns_Log(Notice,">>>> got wlock %x",object_ptr); } void q_release_lock(void *object_ptr) { Tcl_HashEntry *entry; /* * Get a read lock on the locks hashtable, and then release the object lock. * Then release the read lock on the locks hashtable. */ Ns_RWLockRdLock(&g_locks_mutex); entry = Tcl_FindHashEntry(&g_locks, object_ptr); Ns_RWLockUnlock(Tcl_GetHashValue(entry)); Ns_RWLockUnlock(&g_locks_mutex); }