File: cross_process_lock.c

package info (click to toggle)
aws-crt-python 0.24.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 75,932 kB
  • sloc: ansic: 418,984; python: 23,626; makefile: 6,035; sh: 4,075; ruby: 208; java: 82; perl: 73; cpp: 25; xml: 11
file content (93 lines) | stat: -rw-r--r-- 3,470 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
/**
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */
#include <windows.h>

#include <aws/common/byte_buf.h>
#include <aws/common/cross_process_lock.h>
#include <aws/common/error.h>
#include <aws/common/logging.h>
#include <inttypes.h>

struct aws_cross_process_lock {
    struct aws_allocator *allocator;
    HANDLE mutex;
};

struct aws_cross_process_lock *aws_cross_process_lock_try_acquire(
    struct aws_allocator *allocator,
    struct aws_byte_cursor instance_nonce) {

    /* validate we don't have a directory slash. */
    struct aws_byte_cursor to_find = aws_byte_cursor_from_c_str("\\");
    struct aws_byte_cursor found;
    AWS_ZERO_STRUCT(found);
    if (aws_byte_cursor_find_exact(&instance_nonce, &to_find, &found) != AWS_OP_ERR &&
        aws_last_error() != AWS_ERROR_STRING_MATCH_NOT_FOUND) {
        AWS_LOGF_ERROR(
            AWS_LS_COMMON_GENERAL,
            "static: Lock " PRInSTR " creation has illegal character \\",
            AWS_BYTE_CURSOR_PRI(instance_nonce));
        aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
        return NULL;
    }

    struct aws_cross_process_lock *instance_lock = NULL;

    /* "Local\" prefix, per the docs, specifies user session scope (rather than "Global\" to the system). */
    struct aws_byte_cursor path_prefix = aws_byte_cursor_from_c_str("Local\\aws_crt_cross_process_lock/");
    struct aws_byte_buf nonce_buf;
    aws_byte_buf_init_copy_from_cursor(&nonce_buf, allocator, path_prefix);
    aws_byte_buf_append_dynamic(&nonce_buf, &instance_nonce);
    aws_byte_buf_append_null_terminator(&nonce_buf);

    HANDLE mutex = CreateMutexA(NULL, FALSE, (LPCSTR)nonce_buf.buffer);

    if (!mutex) {
        AWS_LOGF_WARN(
            AWS_LS_COMMON_GENERAL,
            "static: Lock %s creation failed with error %" PRIx32,
            (const char *)nonce_buf.buffer,
            GetLastError());
        aws_translate_and_raise_io_error_or(GetLastError(), AWS_ERROR_MUTEX_FAILED);
        goto cleanup;
    }

    /* from the docs:
     * If the mutex is a named mutex and the object existed before this function call, the return value is a handle
     * to the existing object, and the GetLastError function returns ERROR_ALREADY_EXISTS. */
    if (GetLastError() == ERROR_ALREADY_EXISTS) {
        AWS_LOGF_TRACE(
            AWS_LS_COMMON_GENERAL,
            "static: Lock %s is already acquired by another instance",
            (const char *)nonce_buf.buffer);
        CloseHandle(mutex);
        aws_raise_error(AWS_ERROR_MUTEX_CALLER_NOT_OWNER);
        goto cleanup;
    }

    instance_lock = aws_mem_calloc(allocator, 1, sizeof(struct aws_cross_process_lock));
    instance_lock->mutex = mutex;
    instance_lock->allocator = allocator;

    AWS_LOGF_TRACE(
        AWS_LS_COMMON_GENERAL,
        "static: Lock %s acquired by this instance with HANDLE %p",
        (const char *)nonce_buf.buffer,
        (void *)mutex);

cleanup:

    /* we could do this once above but then we'd lose logging for the buffer. */
    aws_byte_buf_clean_up(&nonce_buf);
    return instance_lock;
}

void aws_cross_process_lock_release(struct aws_cross_process_lock *instance_lock) {
    if (instance_lock) {
        CloseHandle(instance_lock->mutex);
        AWS_LOGF_TRACE(AWS_LS_COMMON_GENERAL, "static: Lock released for handle %p", (void *)instance_lock->mutex);
        aws_mem_release(instance_lock->allocator, instance_lock);
    }
}