/* ******************************************************************************* * Copyright (c) 1996 Martin Poole * ******************************************************************************* ** ** WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! WARNING !! ** ** Any changes to be made to this file should first be checked with ** mplib1 source control for library integrity. ** ** mplib1 source control can be reached at mplib1@quatermass.co.uk ** * * $Source: /home/cvs/cvsroot/onelan/onelan/src/mplib1/libsrc/bpo_lock_pid.c,v $ * $Author: mpoole $ * $Date: 2002/10/07 09:37:37 $ * $Revision: 1.2 $ * ******************************************************************************* * * Change History * * $Log: bpo_lock_pid.c,v $ * Revision 1.2 2002/10/07 09:37:37 mpoole * Initial checkin of mplib1-3.1.0 * * Revision 1.1 2002/10/07 09:36:54 mpoole * Initial checkin of mplib1-3.1.0 * * ******************************************************************************* */ #ident "$Header: /home/cvs/cvsroot/onelan/onelan/src/mplib1/libsrc/bpo_lock_pid.c,v 1.2 2002/10/07 09:37:37 mpoole Exp $" /* ------------------------------------------------------------------ Include files ------------------------------------------------------------------ */ #include #include #include #include #include #include #include #include #include #include #include /* ------------------------------------------------------------------ defines ------------------------------------------------------------------ */ static int bpo_lock_debug=0; static char lock_debug_str[]="BPO_LOCK_DEBUG"; static char lock_str[]="bpo_pid_Lock:"; /* ------------------------------------------------------------------ Code starts here ------------------------------------------------------------------ */ /* Now we have some routines to replace the use of sempahores. We have seen a problem on NCR3000 platform where a semaphore constructed with SEM_UNDO does not appear to undo when the process is killed. Either I set up the UNDO facility incorrectly (I don't _think_ so) or there is a bug in the semaphore code on this platform (which wouldn't surprise me). So now we have a replacement which is designed with the following considerations. The lock must be used to in short term control mechanisms. The lock must be clearable by another process if it determines that the locking process has died, and/or optionally has held the lock for too long. */ struct bpo_pid_lock * bpo_Init_pid_lock( struct bpo_pid_lock *bplp, struct timeval *udtp ) { struct timeval def_timeout, *dtp; def_timeout.tv_sec = 1; def_timeout.tv_usec = 0; dtp = (udtp) ? udtp:&def_timeout; if (bplp) { b_Init( &bplp->bpo_pid_lock ); b_Init( &bplp->bpo_unlock ); bplp->lock_pid = (pid_t)0; bplp->pid_cnt = 0; bplp->unlock_pid = (pid_t)0; bplp->flags = 0; memcpy( &bplp->lock_duration, dtp, sizeof(struct timeval) ); memset( &bplp->lock_time, '\0', sizeof(struct timeval) ); } return(bplp); } static void bpo_settimeout( struct timeval *when, struct bpo_pid_lock *bplp ) { /* first we setup how long we will wait */ (void)get_current_timeval( when ); when->tv_usec += bplp->lock_duration.tv_usec; when->tv_sec += bplp->lock_duration.tv_sec; while (when->tv_usec >= 1000000) { when->tv_sec++; when->tv_usec -= 1000000; }; return; } void bpo_pid_Lock( struct bpo_pid_lock *bplp ) { int lc=0; struct timeval tillwhen, now; bpo_lock_debug = (bplp->flags & BPO_PID_F_DEBUG) || get_config_flag( lock_debug_str ); bpo_settimeout( &tillwhen, bplp ); if (bpo_lock_debug) fprintfile(stderr,"%s %p - pid %ld\n", lock_str, bplp, (int)getpid() ); if (bplp->lock_pid != getpid()) { #if defined(HAVE_PTHREADS) || defined(HAVE_MSEM) b_Lock( &bplp->bpo_pid_lock ); #else while ( Xchg( &bplp->bpo_pid_lock ) ) { bpo_take_a_nap(); if (bpo_lock_debug && lc==0) { fprintfile(stderr,"%s Awaiting pid %d\n", lock_str, bplp->lock_pid ); lc++; } (void)get_current_timeval( &now ); if ( timercmp( &now, &tillwhen, > )) { lc=0; while ( Xchg( &bplp->bpo_unlock ) ) { if (bpo_lock_debug && lc==0) fprintfile(stderr,"%s Awaiting unlock\n", lock_str ); if (bplp->lock_pid) bpo_take_a_nap(); else if (lc++>100) Clr( &bplp->bpo_unlock ); }; /* too long, try and clear down */ if (bplp->lock_pid) { if (is_pid_dead( bplp->lock_pid ) ) { if (bpo_lock_debug) fprintfile(stderr,"%s reposessing lock from %d\n", lock_str, (int)bplp->lock_pid ); /* it's gone */ bplp->lock_pid = getpid(); bplp->pid_cnt = 0; Clr( &bplp->bpo_pid_lock ); } }else { Clr( &bplp->bpo_pid_lock ); if (bpo_lock_debug) fprintfile(stderr,"%s reposessing lock\n", lock_str ); } Clr( &bplp->bpo_unlock ); bpo_settimeout( &tillwhen, bplp ); } }; #endif /* Got the lock (for the first time) */ bplp->pid_cnt = 0; } if (bpo_lock_debug) fprintfile(stderr,"%s set TOD & pid\n", lock_str ); /* OK, so take the lock */ get_current_timeval( &bplp->lock_time ); bplp->lock_pid = getpid(); bplp->pid_cnt++; return; } void bpo_pid_Unlock( struct bpo_pid_lock *bplp ) { pid_t my_pid; my_pid = getpid(); bpo_lock_debug = (bplp->flags & BPO_PID_F_DEBUG) || get_config_flag( lock_debug_str ); if (bpo_lock_debug) fprintfile(stderr,"bpo_pid_Unlock: %p(%d) = %d\n", bplp, my_pid, bplp->pid_cnt ); if (bplp) { if (bplp->lock_pid == my_pid) { if (--bplp->pid_cnt == 0) { bplp->lock_pid = (pid_t)0; b_Unlock( &bplp->bpo_pid_lock ); } } } return; } /* -- End of File -- */