safelock.c
/* Atomically fetch the status from an open Safelock */
Atomically fetch the status from an open Safelock
Atomically fetch the status from an open Safelock
int safelock_fetch_status(safelock_t lock, safelock_status_t *status)
{
    lock_data_t *shared;
    int pid_alive, err;
    int lock_in_use = 0;
    int data_mutex_dirty;
    assert(lock);
    assert(status);
    shared = lock->shared;
    err = data_mutex_lock(lock, &data_mutex_dirty);
    if (err)
        return err;
    pid_alive = pid_exists(shared->pid);
    err = owner_mutex_in_use(lock, data_mutex_dirty, &lock_in_use);
    if (err) {
        NOFAIL(pthread_mutex_unlock(&shared->data_mutex));
        return err;
    }
    if (!pid_alive && lock_in_use) {
        NOFAIL(pthread_mutex_unlock(&shared->data_mutex));
        err = safelock_remove(lock);
        return !err ? EINVAL : ENOTRECOVERABLE;
    }
    status->locked = lock_in_use;
    status->crashed = !lock_in_use && shared->taken;
    status->data_valid = shared->data_valid;
    status->pid = shared->pid;
    status->data = shared->data;
    if (lock_in_use) {
        uint64_t now = gettimeofday_us();
        status->age = (now > shared->taken)
                      ? now - shared->taken
                      : 1;
    } else {
        status->age = 0;
    }
    NOFAIL(pthread_mutex_unlock(&shared->data_mutex));
    return 0;
}
int safelock_fetch_status ( safelock_t lock , safelock_status_t * status ) { lock_data_t * shared ; int pid_alive , err ; int lock_in_use = 0 ; int data_mutex_dirty ; assert ( lock ) ; assert ( status ) ; shared = lock -> shared ; err = data_mutex_lock ( lock , & data_mutex_dirty ) ; if ( err ) return err ; pid_alive = pid_exists ( shared -> pid ) ; err = owner_mutex_in_use ( lock , data_mutex_dirty , & lock_in_use ) ; if ( err ) { NOFAIL ( pthread_mutex_unlock ( & shared -> data_mutex ) ) ; return err ; } if ( ! pid_alive && lock_in_use ) { NOFAIL ( pthread_mutex_unlock ( & shared -> data_mutex ) ) ; err = safelock_remove ( lock ) ; return ! err ? EINVAL : ENOTRECOVERABLE ; } status -> locked = lock_in_use ; status -> crashed = ! lock_in_use && shared -> taken ; status -> data_valid = shared -> data_valid ; status -> pid = shared -> pid ; status -> data = shared -> data ; if ( lock_in_use ) { uint64_t now = gettimeofday_us ( ) ; status -> age = ( now > shared -> taken ) ? now - shared -> taken : 1 ; } else { status -> age = 0 ; } NOFAIL ( pthread_mutex_unlock ( & shared -> data_mutex ) ) ; return 0 ; }
Atomically fetch the status from an open Safelock
Atomically fetch the status from an open Safelock
/* Check whether the safelock has been left in a "locked" state
     * (lock in use, but PID doesn't exist). Eg, the robust mutex
     * didn't get cleaned up after a power loss or OS crash.
     *
     * The PID check above must be done before the lock check to ensure
     * there is no false positive when a lock holder dies between the
     * checks.
     *
     * Note, this check is not perfect. A new process may have been
     * created with the same PID. In this situtation the lock will still
     * appear to be in use.
     *
     * The best way to avoid these issues is to remove any lock files
     * after a system crash or power failure. Putting lock files on a
     * TMPFS filesystem is one option. */ /* Return EINVAL if the Safelock has been successfully removed
         * by this (or another) thread. Otherwise advise the caller
         * that the lock must be manually fixed */ /* safelock_unlock() zero's shared->taken to indicate the lock
     * has been cleanly unlocked. */ /* The pid, age and data fields are only valid when:
     * - A safelock owner hasn't crashed holding the data mutex
     * - The safelock has been used at least once */ /* Set to 1 if time went backwards */