1 /*
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright © 2022 Keith Packard
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above
14 * copyright notice, this list of conditions and the following
15 * disclaimer in the documentation and/or other materials provided
16 * with the distribution.
17 *
18 * 3. Neither the name of the copyright holder nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
29 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
31 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
33 * OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #define _DEFAULT_SOURCE
37 #include <stdint.h>
38 #include <assert.h>
39 #include <stdlib.h>
40
41 /*
42 * Validate lock usage in libc by creating fake locks
43 * to be used during testing
44 */
45
46 #define _LOCK_T intptr_t*
47
48 intptr_t __lock___libc_recursive_mutex;
49
50 #define MAX_LOCKS 32
51
52 static intptr_t locks[MAX_LOCKS];
53 static int lock_id;
54
55 /* Create a new dynamic non-recursive lock */
__retarget_lock_init(_LOCK_T * lock)56 void __retarget_lock_init(_LOCK_T *lock)
57 {
58 assert(lock_id < MAX_LOCKS);
59 *lock = &locks[lock_id++];
60 **lock = 0;
61 }
62
63 /* Create a new dynamic recursive lock */
__retarget_lock_init_recursive(_LOCK_T * lock)64 void __retarget_lock_init_recursive(_LOCK_T *lock)
65 {
66 *lock = &locks[lock_id++];
67 **lock = 0;
68 }
69
70 /* Close dynamic non-recursive lock */
__retarget_lock_close(_LOCK_T lock)71 void __retarget_lock_close(_LOCK_T lock)
72 {
73 assert(*lock == 0);
74 }
75
76 /* Close dynamic recursive lock */
__retarget_lock_close_recursive(_LOCK_T lock)77 void __retarget_lock_close_recursive(_LOCK_T lock)
78 {
79 assert(*lock == 0);
80 }
81
82 /* Acquiure non-recursive lock */
__retarget_lock_acquire(_LOCK_T lock)83 void __retarget_lock_acquire(_LOCK_T lock)
84 {
85 assert(*lock == 0);
86 *lock = 1;
87 }
88
89 /* Acquiure recursive lock */
__retarget_lock_acquire_recursive(_LOCK_T lock)90 void __retarget_lock_acquire_recursive(_LOCK_T lock)
91 {
92 assert(*lock >= 0);
93 ++(*lock);
94 }
95
96 /* Try acquiring non-recursive lock */
__retarget_lock_try_acquire(_LOCK_T lock)97 int __retarget_lock_try_acquire(_LOCK_T lock)
98 {
99 assert(*lock == 0);
100 *lock = 1;
101 }
102
103 /* Try acquiring recursive lock */
__retarget_lock_try_acquire_recursive(_LOCK_T lock)104 int __retarget_lock_try_acquire_recursive(_LOCK_T lock)
105 {
106 assert(*lock >= 0);
107 ++(*lock);
108 }
109
110 /* Release non-recursive lock */
__retarget_lock_release(_LOCK_T lock)111 void __retarget_lock_release(_LOCK_T lock)
112 {
113 assert(*lock == 1);
114 *lock = 0;
115 }
116
117 /* Release recursive lock */
__retarget_lock_release_recursive(_LOCK_T lock)118 void __retarget_lock_release_recursive(_LOCK_T lock)
119 {
120 assert(*lock > 0);
121 --(*lock);
122 }
123
124 #ifdef _PICO_EXIT
125 #define LIBC_LOCK_EXIT_COUNT 0
126 #else
127 /*
128 * Legacy onexit handler holds libc lock while calling hooks
129 */
130 #define LIBC_LOCK_EXIT_COUNT 1
131 #endif
132
lock_validate(int ret,void * arg)133 static void lock_validate(int ret, void *arg)
134 {
135 int i;
136 (void) ret;
137 (void) arg;
138 for (i = 0; i < MAX_LOCKS; i++)
139 assert(locks[i] == 0);
140
141 assert(__lock___libc_recursive_mutex == LIBC_LOCK_EXIT_COUNT);
142 }
143
144 __attribute__((constructor))
add_lock_validate(void)145 static void add_lock_validate(void)
146 {
147 on_exit(lock_validate, NULL);
148 }
149