---
name: "ggTryLock"
section: "3"
platform: "linux"
package: "libgii1"
version: "1:1.0.2-4.1"
release: "Debian 7 (Wheezy)"
platforms: ["linux"]
url: "https://new.carta.tech/ggLockCreate"
---

# ggTryLock(3)

Lowest common denominator locking facilities

Part of [ggLockCreate(3)](/ggLockCreate/3.md).

## NAME

**ggLockCreate**, **ggLockDestroy**, **ggLock**, **ggUnlock**, **ggTryLock** - Lowest common denominator locking facilities

## SYNOPSIS

```
#include <ggi/gg.h>
void *ggLockCreate(void);
int ggLockDestroy(void *lock);
void ggLock(void *lock);
void ggUnlock(void *lock);
int ggTryLock(void *lock);
```

## DESCRIPTION

These functions allow sensitive resource protection to prevent  simultaneous or interleaved access to resources.  For developers accustomed to POSIX-like threading environments it is important to  differentiate a gglock from a "mutex".  A gglock fills **\*both\***  the role of a "mutex" and a "condition" (a.k.a. an "event" or  "waitqueue") through a simplified API, and as such there is no such thing as a gglock "owner".  A LibGG lock is just locked or  unlocked, it does not matter by what or when as long as the application  takes care never to create a deadlock that never gets broken.

The locking mechanisms are fully functional even in single-threaded,  uninterrupted-flow-of-control environments.   They must still be used  as described below even in these environments; They are never reduced  to non-operations.

The locking mechanisms are threadsafe, and are also safe to call from inside LibGG task handlers.  However, they are not safe to use in a thread that may be cancelled during their execution, and they are not guaranteed to be safe to use in any special context other than a LibGG task, such as a signal handler or asyncronous procedure call.

Though the LibGG API does provide ample functionality for threaded environments, do note that LibGG does not itself define any sort of  threading support, and does not require or guarantee that threads  are available.  As such, if the aim of an application developer is to remain as portable as possible, they should keep in mind that when coding for both environments, there are only two situations where locks are appropriate to use.  These two situations are  described in the examples below.

Cleanup handlers created with `ggRegisterCleanup(3)` should not  call any of these functions.

LibGG must be compiled with threading support if multiple threads  that call any of these functions are to be used in the program. When LibGG is compiled with threading support, the **ggLock**, **ggUnlock**,  and **ggTryLock** functions are guaranteed memory barriers for the  purpose of multiprocessor data access synchronization.  (When LibGG  is not compiled with threading support, it does not matter, since  separate threads should not be using these functions in the first  place.)

**ggLockCreate** creates a new lock.  The new lock is initially unlocked.

**ggLockDestroy** destroys a *lock*, and should only be called when *lock* is unlocked, otherwise the results are undefined and probably undesirable.

**ggLock** will lock the *lock* and return immediately, but only if the *lock* is unlocked.  If the *lock* is locked, **ggLock** will not return until the *lock* gets unlocked by a later call to  **ggUnlock**.  In either case *lock* will be locked when **ggLock** returns.   **ggLock** is "atomic," such that only one waiting call to **ggLock** will  return (or one call to **ggTryLock** will return successfully) each  time *lock* is unlocked.  Order is **\*not\*** guaranteed by LibGG --  if two calls to **ggLock** are made at different times on the same  *lock*, either one may return when the *lock* is unlocked  regardless of which call was made first.  (It is even possible  for a call to **ggTryLock** to grab the *lock* right after it is  unlocked, even though a call to **ggLock** was already waiting on the  *lock*.)

**ggTryLock** attempts to lock the *lock*, but unlike **ggLock** it always returns immediately whether or not the *lock* was locked  to begin with.  The return value indicates whether the *lock* was  locked at the time **ggTryLock** was invoked.  In either case *lock*  will be locked when **ggTryLock** returns.

**ggUnlock** unlocks the *lock*.  If any calls to **ggLock** or **ggTryLock** are subsequently invoked, or have previously been invoked on  the *lock*, one of the calls will lock *lock* and return. As noted above, which **ggLock** call returns is not specified by LibGG and any observed behavior should not be relied upon.  Immediacy is  also **\*not\*** guaranteed; a waiting call to **ggLock** may take some time  to return.  **ggUnlock** may be called, successfully, even if *lock*  is already unlocked, in which case, nothing will happen (other than a memory barrier.)

In all the above functions, where required, the *lock* parameter  **\*must\*** be a valid lock, or the results are undefined, may contradict  what is written here, and, in general, bad and unexpected things might happen to you and your entire extended family.  The functions do  **\*not\*** validate the *lock*; It is the responsibility of the calling  code to ensure it is valid before it is used.

Remember, locking is a complicated issue (at least, when coding for multiple environments) and should be a last resort.

## RETURN VALUE

**ggLockCreate** returns a non-NULL opaque pointer to a mutex, hiding  its internal implementation.  On failure, ggLockCreate returns **NULL**.

**ggTryLock** returns **GGI\_OK** if the lock was unlocked, or **GGI\_EBUSY** if the lock was already locked.

**ggLockDestroy** returns **GGI\_OK** on success or **GGI\_EBUSY** if the lock is locked.

## EXAMPLES

One use of gglocks is to protect a critical section, for example access to a global variable, such that the critical section is never entered by more than one thread when a function is called in a multi-threaded environment.  It is important for developers working in a single-threaded environment to consider the needs of multi-threaded environments when  they provide a function for use by others.

```
static int foo = 0;
static gglock *l;
void increment_foo(void) {
    ggLock(l);
    foo++;
    ggUnlock(l);
}
```

In the above example, it is assumed that gglock is initialized using **ggLockCreate** before any calls to increment\_foo are made.  Also note that in the above example, when writing for maximum portability, increment\_foo  should not be called directly or indirectly by a task handler which was registered via ggAddTask because a deadlock may result (unless it is  somehow known that increment\_foo is not being executed by any code outside  the task handler.)

Another use of gglocks is to delay or skip execution of a task handler registered with **[ggAddTask(3)](/ggAddTask/3.md)**.  It is important for developers working  in a multi-threaded environment to consider this when they use tasks, because in single-threaded environments tasks interrupt the flow of control and may in fact themselves be immune to interruption.  As such they  cannot wait for a locked lock to become unlocked -- that would create a deadlock.

```
static gglock *t, *l, *s;
int misscnt = 0;
void do_foo (void) {
       ggLock(t);              /* prevent reentry            */
       ggLock(l);              /* keep task out              */
       do_something();
       ggUnlock(l);            /* task OK to run again       */
       if (!ggTryLock(s)) {    /* run task if it was missed  */
               if (misscnt) while (misscnt--) do_something_else();
               ggUnlock(s);
       }
       ggUnlock(t);            /* end of critical section    */
}
/* This is called at intervals by the LibGG scheduler */
static int task_handler(struct gg_task *task) {
      int do_one;
      /* We know the main application never locks s and l at the
       * same time.  We also know it never locks either of the
       * two more than once (e.g. from more than one thread.)
       */
      if (!ggTryLock(s)) {
             /* Tell the main application to run our code for us
              * in case we get locked out and cannot run it ourselves.
              */
             misscnt++;
             ggUnlock(s);
             if (ggTryLock(l)) return; /* We got locked out. */
      } else {
             /* The main application is currently running old missed
              * tasks.  But it is using misscnt, so we can't just ask
              * it to do one more.
              *
              * If this is a threaded environment, we may spin here for
              * while in the rare case that the main application
              * unlocked s and locked l between the above ggTryLock(s)
              * and the below ggLock(l).  However we will get control
              * back eventually.
              *
              * In a non-threaded environment, the below ggLock cannot
              * wedge, because the main application is stuck inside the
              * section where s is locked, so we know l is unlocked.
              */
             ggLock(l);
             do_something_else();
             ggUnlock(l);
             return;
      }
      /* now we know it is safe to run do_something_else() as
       * do_something() cannot be run until we unlock l.
       * However, in threaded environments, the main application may
       * have just started running do_something_else() for us already.
       * If so, we are done, since we already incremented misscnt.
       * Otherwise we must run it ourselves, and decrement misscnt
       * so it won't get run an extra time when we unlock s.
       */
      if (ggTryLock(s)) return;
      if (misscnt) while (misscnt--) do_something_else();
      ggUnlock(s);
      ggUnlock(l);
}
```

In the above example, the lock t prevents reentry into the dofoo subroutine the same as the last example.  The lock l prevents  do\_something\_else() from being called while do\_something() is running.   The lock s is being used to protect the misscnt variable and also acts as a memory barrier to guarantee that the value seen in misscnt is up-to-date.   The code in function dofoo will run do\_something\_else()  after do\_something() if the task happened while do\_something() was  running.  The above code will work in multi-threaded-single-processor,  multi-threaded-multi-processor, and single-threaded environments.

**Note:** The above code assumes do\_something\_else() is reentrant.

## SEE ALSO

`pthread_mutex_init(3)`
