NAME

smartLock - Attempts to lock a smart lock.

SYNOPSIS

#include <game-carrier/server.h>

typedef GCT_INT (GC_CORE_API *SmartLock)(
    GCT_INTPTR lock);

typedef struct smartLock {
    /* ... Some fields ... */
    SmartLock smartLock;
    /* ... Some fields ... */
}

Parameters:

  • lock GCT_INTPTR Smart lock handle

RETURN VALUE

Returns SMART_LOCK_OK (0) if the lock was successfully acquired, or SMART_LOCK_DESTROYED (1) if an error occurred.

DESCRIPTION

The smartLock function attempts to acquire a smart lock. It is used to protect critical sections of code from concurrent access.

The lock argument is the handle of the smart lock to be acquired. It might be created using the smartLockCreate function.

Smart locks provide cross platform way to operate with mutexes. It can be useful for interactring between different programming languages.

Released smart locks handles can be reallocated again only after a timeout. It helps to prevent races if an object associated with a smart lock is destroyed. The smartLock function will return SMART_LOCK_DESTROYED (1) if the lock was destroyed before it could be acquired.

EXAMPLE

#include <game-carrier/server.h>

#include <errno.h>
#include <stddef.h>
#include <stdlib.h>

static struct core_api api;

struct dlist {
    struct dlist * prev;
    struct dlist * next;
};

GCT_INTPTR primary_lock;
struct dlist root;

struct connection_data {
    GCT_INTPTR handle;
    GCT_INTPTR lock;
    struct dlist link;
    /* User data asociated with connection */
};

static struct connection_data * get_owner(struct dlist * link)
{
    if (link == &root) {
        return NULL;
    }
    intptr_t address = (intptr_t) link;
    address -= offsetof(struct connection_data, link);
    return (void*) address;
}

GC_ADAPTER_EVENT
int adapter_initialize(int id, struct core_api *core_api, const void *load_path)
{
    api = *core_api;
    primary_lock = api.smartLockCreate();
    if (primary_lock == 0) {
        return ENOMEM;
    }
    root.next = &root;
    root.prev = &root;
    return 0;
}

GC_ADAPTER_EVENT
void adapter_finalize(GCT_INT id)
{
    api.smartLockDestroy(primary_lock);
}

GC_ADAPTER_EVENT
GCT_INTPTR on_connect(
    GCT_INT app_id,
    GCT_INTPTR handle,
    GCT_INT pid,
    GCT_CSTR rip,
    GCT_INT rport,
    GCT_CSTR lip,
    GCT_INT lport,
    GCT_CSTR udata)
{
    /* Allocate user data */
    struct connection_data * conn = malloc(sizeof(struct connection_data));
    if (conn == NULL) {
        return GC_DROP_CONNECTION;
    }

    /* Create a connection lock */
    GCT_INTPTR lock = api.smartLockCreate();
    if (lock == 0) {
        free(conn);
        return GC_DROP_CONNECTION;
    }

    /* Initialize user data */
    conn->handle = handle;
    conn->lock = lock;

    /* Insert conn to a global list */
    /* Lock result is not checked for global locks.*/
    api.smartLock(primary_lock);
    conn->link.next = root.next;
    conn->link.prev = &root;
    root.next->prev = &conn->link;
    root.next = &conn->link;
    api.smartUnlock(primary_lock);

    /* Return user data */
    return (GCT_INTPTR)conn;
}

GC_ADAPTER_EVENT
void on_disconnect(
    GCT_INTPTR user)
{
    struct connection_data * data = (struct connection_data *)user;

    /* Remove conn from a global list */
    /* Lock result is not checked for global locks. */
    api.smartLock(primary_lock);
    data->link.next->prev = data->link.prev;
    data->link.prev->next = data->link.next;
    api.smartUnlock(primary_lock);

    /* Destroy connection lock */
    api.smartLockDestroy(data->lock);

    /* Free user data */
    free(data);
}

GC_ADAPTER_EVENT
void on_message(
    GCT_INTPTR user,
    GCT_PTR data,
    GCT_SIZE len)
{
    struct connection_data * conn = (struct connection_data *)user;

    /* Get the next connection */
    /* Lock result is not checked for global locks.*/
    api.smartLock(primary_lock);
    struct connection_data * next_conn = get_owner(conn->link.next);
    GCT_INTPTR next_lock = next_conn ? next_conn->lock : 0;
    api.smartUnlock(primary_lock);

    /* Your custom logic */

    /* Your custom logic for the next connection */
    if (next_conn) {
        if (api.smartLock(next_lock) != SMART_LOCK_DESTROYED) {
            /* Next connection is not disconnected yet, do something with it */
            api.smartUnlock(primary_lock);
        }
    }
}

SEE ALSO

gc_smartlock_status, smartLockCreate, smartLockDestroy, smartUnlock