1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2/******************************************************************************
3 *
4 * Module Name: utlock - Reader/Writer lock interfaces
5 *
6 * Copyright (C) 2000 - 2023, Intel Corp.
7 *
8 *****************************************************************************/
9
10#include <acpi/acpi.h>
11#include "accommon.h"
12
13#define _COMPONENT          ACPI_UTILITIES
14ACPI_MODULE_NAME("utlock")
15
16/*******************************************************************************
17 *
18 * FUNCTION:    acpi_ut_create_rw_lock
19 *              acpi_ut_delete_rw_lock
20 *
21 * PARAMETERS:  lock                - Pointer to a valid RW lock
22 *
23 * RETURN:      Status
24 *
25 * DESCRIPTION: Reader/writer lock creation and deletion interfaces.
26 *
27 ******************************************************************************/
28acpi_status acpi_ut_create_rw_lock(struct acpi_rw_lock *lock)
29{
30	acpi_status status;
31
32	lock->num_readers = 0;
33	status = acpi_os_create_mutex(&lock->reader_mutex);
34	if (ACPI_FAILURE(status)) {
35		return (status);
36	}
37
38	status = acpi_os_create_mutex(&lock->writer_mutex);
39	return (status);
40}
41
42void acpi_ut_delete_rw_lock(struct acpi_rw_lock *lock)
43{
44
45	acpi_os_delete_mutex(lock->reader_mutex);
46	acpi_os_delete_mutex(lock->writer_mutex);
47
48	lock->num_readers = 0;
49	lock->reader_mutex = NULL;
50	lock->writer_mutex = NULL;
51}
52
53/*******************************************************************************
54 *
55 * FUNCTION:    acpi_ut_acquire_read_lock
56 *              acpi_ut_release_read_lock
57 *
58 * PARAMETERS:  lock                - Pointer to a valid RW lock
59 *
60 * RETURN:      Status
61 *
62 * DESCRIPTION: Reader interfaces for reader/writer locks. On acquisition,
63 *              only the first reader acquires the write mutex. On release,
64 *              only the last reader releases the write mutex. Although this
65 *              algorithm can in theory starve writers, this should not be a
66 *              problem with ACPICA since the subsystem is infrequently used
67 *              in comparison to (for example) an I/O system.
68 *
69 ******************************************************************************/
70
71acpi_status acpi_ut_acquire_read_lock(struct acpi_rw_lock *lock)
72{
73	acpi_status status;
74
75	status = acpi_os_acquire_mutex(lock->reader_mutex, ACPI_WAIT_FOREVER);
76	if (ACPI_FAILURE(status)) {
77		return (status);
78	}
79
80	/* Acquire the write lock only for the first reader */
81
82	lock->num_readers++;
83	if (lock->num_readers == 1) {
84		status =
85		    acpi_os_acquire_mutex(lock->writer_mutex,
86					  ACPI_WAIT_FOREVER);
87	}
88
89	acpi_os_release_mutex(lock->reader_mutex);
90	return (status);
91}
92
93acpi_status acpi_ut_release_read_lock(struct acpi_rw_lock *lock)
94{
95	acpi_status status;
96
97	status = acpi_os_acquire_mutex(lock->reader_mutex, ACPI_WAIT_FOREVER);
98	if (ACPI_FAILURE(status)) {
99		return (status);
100	}
101
102	/* Release the write lock only for the very last reader */
103
104	lock->num_readers--;
105	if (lock->num_readers == 0) {
106		acpi_os_release_mutex(lock->writer_mutex);
107	}
108
109	acpi_os_release_mutex(lock->reader_mutex);
110	return (status);
111}
112
113/*******************************************************************************
114 *
115 * FUNCTION:    acpi_ut_acquire_write_lock
116 *              acpi_ut_release_write_lock
117 *
118 * PARAMETERS:  lock                - Pointer to a valid RW lock
119 *
120 * RETURN:      Status
121 *
122 * DESCRIPTION: Writer interfaces for reader/writer locks. Simply acquire or
123 *              release the writer mutex associated with the lock. Acquisition
124 *              of the lock is fully exclusive and will block all readers and
125 *              writers until it is released.
126 *
127 ******************************************************************************/
128
129acpi_status acpi_ut_acquire_write_lock(struct acpi_rw_lock *lock)
130{
131	acpi_status status;
132
133	status = acpi_os_acquire_mutex(lock->writer_mutex, ACPI_WAIT_FOREVER);
134	return (status);
135}
136
137void acpi_ut_release_write_lock(struct acpi_rw_lock *lock)
138{
139
140	acpi_os_release_mutex(lock->writer_mutex);
141}
142