GCC Code Coverage Report


Directory: ../src/
File: /home/joels/Current/lispbm/src/extensions/mutex_extensions.c
Date: 2025-08-08 18:10:24
Exec Total Coverage
Lines: 56 65 86.2%
Functions: 9 9 100.0%
Branches: 24 34 70.6%

Line Branch Exec Source
1 /*
2 Copyright 2025 Joel Svensson svenssonjoel@yahoo.se
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 #include "extensions/mutex_extensions.h"
19
20 #include "extensions.h"
21 #include "eval_cps.h"
22
23 #ifdef LBM_OPT_MUTEX_EXTENSIONS_SIZE
24 #pragma GCC optimize ("-Os")
25 #endif
26 #ifdef LBM_OPT_MUTEX_EXTENSIONS_SIZE_AGGRESSIVE
27 #pragma GCC optimize ("-Oz")
28 #endif
29
30
31 // This file provides a mutual exclusion feature based on the block_from_extension
32 // mechanism present in LBM.
33 //
34 // Three operations are provided:
35 // - mutex-create
36 // - mutex-lock
37 // - mutex-unlock
38 //
39 // It is strongly adviced to use these as a low-level interface and then to wrap
40 // them up in a (with-mutex-do mutex expr) that implements the locking and unlocking
41 // so that no mutex is left dangling.
42 //
43 // with-mutex-do can be implemented as
44 //
45 // (define with-mutex-do (lambda (mutex quoted-expr)
46 // (progn (mutex-lock mutex)
47 // (eval quoted-expr)
48 // (mutex-unlock mutex)
49 //
50 //
51 // The mutex object is a dotted pair (ls . last) which contains
52 // two references into a single list, implementing a O(1)-insert-last O(1)-remove-first
53 // queue. At the surface though, it is a regular lisp dotted pair that
54 // can be destroyed with standard lisp functionality, no protection!
55 // When a good replacement for "Custom types" is invented this will be improved.
56
57 306 bool is_mutex(lbm_value v) {
58 // true if it is somewhat likely that v is a mutex.
59
2/2
✓ Branch 0 taken 299 times.
✓ Branch 1 taken 7 times.
605 bool res = (lbm_is_cons(v) &&
60
3/4
✓ Branch 0 taken 152 times.
✓ Branch 1 taken 147 times.
✓ Branch 2 taken 152 times.
✗ Branch 3 not taken.
299 (!lbm_is_symbol_nil(lbm_car(v)) || lbm_is_symbol_nil(lbm_cdr(v)))); // car == nil -> cdr == nil
61 // potentially add a clause
62 // car == (cons a b) -> cdr == (cons c nil)
63 306 return res;
64 }
65
66 299 bool is_mutex_unlocked(lbm_value v) {
67 299 return (lbm_is_symbol_nil(lbm_car(v)));
68 }
69
70 148 void enqueue_cid(lbm_value mutex, lbm_value cid_pair) {
71
1/2
✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
148 if (lbm_is_symbol_nil(lbm_car(mutex))) {
72 148 lbm_set_car(mutex, cid_pair);
73 148 lbm_set_cdr(mutex, cid_pair);
74 } else {
75 lbm_value last = lbm_cdr(mutex);
76 lbm_set_cdr(last, cid_pair);
77 lbm_set_cdr(mutex, cid_pair);
78 }
79 148 }
80
81 147 bool dequeue_cid(lbm_value mutex, lbm_value cid) {
82 147 bool res = false;
83
1/2
✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
147 if (lbm_is_cons(lbm_car(mutex))) {
84 147 lbm_value locked_cid = lbm_car(lbm_car(mutex));
85
1/2
✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
147 if (locked_cid == cid) { // no decoding
86 147 res = true;
87 147 lbm_value head = lbm_car(mutex);
88 147 lbm_value last = lbm_cdr(mutex);
89
1/2
✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
147 if (head == last) { // one element
90 147 lbm_set_car(mutex, ENC_SYM_NIL);
91 147 lbm_set_cdr(mutex, ENC_SYM_NIL);
92 } else {
93 lbm_set_car(mutex, lbm_cdr(head));
94 }
95 }
96 }
97 147 return res;
98 }
99
100 147 lbm_value head_of_queue(lbm_value mutex) {
101 147 lbm_value res = ENC_SYM_NIL;
102
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 147 times.
147 if (lbm_is_cons(lbm_car(mutex))) {
103 res = lbm_car(lbm_car(mutex));
104 }
105 147 return res;
106 }
107
108 102 static lbm_value ext_mutex_create(lbm_value *args, lbm_uint argn) {
109 (void) args;
110 (void) argn;
111 102 return lbm_cons(ENC_SYM_NIL, ENC_SYM_NIL);
112 }
113
114 154 static lbm_value ext_mutex_lock(lbm_value *args, lbm_uint argn) {
115 154 lbm_value res = ENC_SYM_TERROR;
116
4/4
✓ Branch 0 taken 152 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 148 times.
✓ Branch 3 taken 4 times.
154 if (argn == 1 && is_mutex(args[0])) {
117 148 lbm_cid cid = lbm_get_current_cid();
118 148 lbm_value cid_pair = lbm_cons(lbm_enc_i(cid), ENC_SYM_NIL);
119 148 res = cid_pair; // Return the error from cons if failed.
120
1/2
✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
148 if (lbm_is_cons(cid_pair)) {
121 148 res = ENC_SYM_TRUE;
122
1/2
✓ Branch 0 taken 148 times.
✗ Branch 1 not taken.
148 if (is_mutex_unlocked(args[0])) {
123 148 enqueue_cid(args[0], cid_pair);
124 } else {
125 enqueue_cid(args[0], cid_pair);
126 lbm_block_ctx_from_extension();
127 }
128 }
129 }
130 154 return res;
131 }
132
133 156 static lbm_value ext_mutex_unlock(lbm_value *args, lbm_uint argn) {
134 156 lbm_value res = ENC_SYM_TERROR;
135
4/4
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 151 times.
✓ Branch 3 taken 3 times.
156 if (argn == 1 && is_mutex(args[0])) {
136 151 res = ENC_SYM_EERROR; // no mutex is locked!
137
2/2
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 4 times.
151 if (!is_mutex_unlocked(args[0])) {
138 147 lbm_cid cid = lbm_get_current_cid(); // this cid should be top of queue!
139 // otherwise error
140
1/2
✓ Branch 0 taken 147 times.
✗ Branch 1 not taken.
147 if (dequeue_cid(args[0], lbm_enc_i(cid))) {
141 147 lbm_value h = head_of_queue(args[0]);
142 147 res = ENC_SYM_TRUE;
143
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 147 times.
147 if (!lbm_is_symbol_nil(h)) {
144 lbm_cid unblock = lbm_dec_i(h);
145 lbm_unblock_ctx_unboxed(unblock, ENC_SYM_TRUE);
146 }
147 }
148 }
149 }
150 156 return res;
151 }
152
153
154 44260 void lbm_mutex_extensions_init(void) {
155 44260 lbm_add_extension("mutex-create", ext_mutex_create);
156 44260 lbm_add_extension("mutex-lock", ext_mutex_lock);
157 44260 lbm_add_extension("mutex-unlock", ext_mutex_unlock);
158 44260 }
159