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
14  ACPI_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   ******************************************************************************/
acpi_ut_create_rw_lock(struct acpi_rw_lock * lock)28  acpi_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  
acpi_ut_delete_rw_lock(struct acpi_rw_lock * lock)42  void 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  
acpi_ut_acquire_read_lock(struct acpi_rw_lock * lock)71  acpi_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  
acpi_ut_release_read_lock(struct acpi_rw_lock * lock)93  acpi_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  
acpi_ut_acquire_write_lock(struct acpi_rw_lock * lock)129  acpi_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  
acpi_ut_release_write_lock(struct acpi_rw_lock * lock)137  void acpi_ut_release_write_lock(struct acpi_rw_lock *lock)
138  {
139  
140  	acpi_os_release_mutex(lock->writer_mutex);
141  }
142