libcoap
4.3.5
Toggle main menu visibility
Loading...
Searching...
No Matches
coap_threadsafe_internal.h
Go to the documentation of this file.
1
/*
2
* coap_threadsafe_internal.h -- Mapping of threadsafe functions
3
*
4
* Copyright (C) 2023-2024 Jon Shallow <supjps-libcoap@jpshallow.com>
5
*
6
* SPDX-License-Identifier: BSD-2-Clause
7
*
8
* This file is part of the CoAP library libcoap. Please see README for terms
9
* of use.
10
*/
11
16
23
24
#ifndef COAP_THREADSAFE_INTERNAL_H_
25
#define COAP_THREADSAFE_INTERNAL_H_
26
27
/*
28
* Support thread safe access into libcoap
29
*
30
* Locking at different component levels (i.e context and session) is
31
* problematic in that coap_process_io() needs to lock the context as
32
* it scans for all the sessions and then could lock the session being
33
* processed as well - but context needs to remain locked as a list is
34
* being scanned.
35
*
36
* Then if the session process needs to update context ( e.g. delayqueue),
37
* context needs to be locked. So, if coap_send() is done on a session,
38
* it has to be locked, but a retransmission of a PDU by coap_process_io()
39
* has the context already locked.
40
*
41
* However, when the context is going away (coap_free_context()), other
42
* threads may still be access the lock in what is now freed memory.
43
* A solution (by flagging being freed), worked, but still with a timing
44
* window wen the context was finally de-allocated. Coverity Scan did
45
* not like the solution.
46
*
47
* So the initial support for thread safe is done at global lock level
48
* using global_lock. However, context is provided as a parameter should
49
* context level locking be subsequently used.
50
*
51
* Any public API call needs to potentially lock global_lock.
52
*
53
* If a public API needs thread safe protection, the coap_X() function
54
* locks the global_lock lock, calls the coap_X_lkd() function
55
* that does all the work and on return unlocks the global_lock before
56
* returning to the caller of coap_X(). These coap_X() functions
57
* need COAP_API in their definitions.
58
*
59
* Any internal libcoap calls that are to the public API coap_X() must call
60
* coap_X_lkd() if the calling code is already locked.
61
* [The compiler will throw out a deprecation warning against any internal
62
* libcoap call to a COAP_API labelled function]
63
*
64
* Any call-back into app space must be done by using the coap_lock_callback()
65
* (or coap_lock_callback_ret()) wrapper where the global_lock remains locked.
66
*
67
* Note:
68
* libcoap may call a handler, which may in turn call into libcoap, which may
69
* then call a handler. global_lock will remain locked thoughout this process
70
* by the same thread.
71
*
72
* Alternatively, coap_lock_callback_release() (or
73
* coap_lock_callback_ret_release()), is used where the global_lock is unlocked
74
* for the duration of the call-back. Used for things like a request
75
* handler which could be busy for some time.
76
*
77
* Note: On return from the call-back, the code has to be careful not to
78
* use memory locations that may have been updated in the call-back by
79
* calling a Public API.
80
*
81
* Any wait on select() or equivalent when a thread is waiting on an event
82
* must be preceded by unlock global_lock, and then global_lock re-locked after
83
* return;
84
*
85
* To check for recursive deadlock coding errors, COAP_THREAD_RECURSIVE_CHECK
86
* needs to be defined.
87
*
88
* If thread safe is not enabled, then locking of the global_lock does not take
89
* place.
90
*/
91
92
#if COAP_THREAD_SAFE
93
94
# if COAP_THREAD_RECURSIVE_CHECK
95
96
/*
97
* Locking, with deadlock detection
98
*/
99
typedef
struct
coap_lock_t
{
100
coap_mutex_t
mutex;
101
coap_thread_pid_t
pid;
102
const
char
*lock_file;
103
unsigned
int
lock_line;
104
unsigned
int
unlock_line;
105
const
char
*unlock_file;
106
const
char
*callback_file;
107
unsigned
int
callback_line;
108
unsigned
int
in_callback;
109
unsigned
int
lock_count;
110
}
coap_lock_t
;
111
123
void
coap_lock_unlock_func(
const
char
*file,
int
line);
124
138
int
coap_lock_lock_func(
const
char
*file,
int
line);
139
156
#define coap_lock_lock(c,failed) do { \
157
if (!coap_lock_lock_func(__FILE__, __LINE__)) { \
158
failed; \
159
} \
160
} while (0)
161
171
#define coap_lock_unlock(c) do { \
172
coap_lock_unlock_func(__FILE__, __LINE__); \
173
} while (0)
174
185
#define coap_lock_callback(c,func) do { \
186
coap_lock_check_locked(c); \
187
global_lock.in_callback++; \
188
global_lock.callback_file = __FILE__; \
189
global_lock.callback_line = __LINE__; \
190
func; \
191
global_lock.in_callback--; \
192
} while (0)
193
206
#define coap_lock_callback_ret(r,c,func) do { \
207
coap_lock_check_locked(c); \
208
global_lock.in_callback++; \
209
global_lock.callback_file = __FILE__; \
210
global_lock.callback_line = __LINE__; \
211
(r) = func; \
212
global_lock.in_callback--; \
213
} while (0)
214
226
#define coap_lock_callback_release(c,func,failed) do { \
227
coap_lock_check_locked(c); \
228
coap_lock_unlock(c); \
229
func; \
230
coap_lock_lock(c,failed); \
231
} while (0)
232
246
#define coap_lock_callback_ret_release(r,c,func,failed) do { \
247
coap_lock_check_locked(c); \
248
coap_lock_unlock(c); \
249
(r) = func; \
250
coap_lock_lock(c,failed); \
251
} while (0)
252
253
extern
coap_lock_t
global_lock;
254
255
# else
/* ! COAP_THREAD_RECURSIVE_CHECK */
256
257
/*
258
* Locking, but no deadlock detection
259
*/
260
typedef
struct
coap_lock_t
{
261
coap_mutex_t
mutex;
262
coap_thread_pid_t
pid;
263
uint32_t in_callback;
264
volatile
uint32_t lock_count;
265
}
coap_lock_t
;
266
276
void
coap_lock_unlock_func(
void
);
277
288
int
coap_lock_lock_func(
void
);
289
306
#define coap_lock_lock(c,failed) do { \
307
if (!coap_lock_lock_func()) { \
308
failed; \
309
} \
310
} while (0)
311
321
#define coap_lock_unlock(c) do { \
322
assert(c); \
323
coap_lock_unlock_func(); \
324
} while (0)
325
336
#define coap_lock_callback(c,func) do { \
337
coap_lock_check_locked(c); \
338
global_lock.in_callback++; \
339
func; \
340
global_lock.in_callback--; \
341
} while (0)
342
355
#define coap_lock_callback_ret(r,c,func) do { \
356
coap_lock_check_locked(c); \
357
global_lock.in_callback++; \
358
global_lock.in_callback++; \
359
(r) = func; \
360
global_lock.in_callback--; \
361
} while (0)
362
374
#define coap_lock_callback_release(c,func,failed) do { \
375
coap_lock_check_locked(c); \
376
coap_lock_unlock(c); \
377
func; \
378
coap_lock_lock(c,failed); \
379
} while (0)
380
394
#define coap_lock_callback_ret_release(r,c,func,failed) do { \
395
coap_lock_check_locked(c); \
396
coap_lock_unlock(c); \
397
(r) = func; \
398
coap_lock_lock(c,failed); \
399
} while (0)
400
401
# endif
/* ! COAP_THREAD_RECURSIVE_CHECK */
402
406
#define coap_lock_init() do { \
407
memset(&global_lock.mutex, 0, sizeof(global_lock.mutex)); \
408
coap_mutex_init(&global_lock.mutex); \
409
} while (0)
410
414
#define coap_lock_check_locked(c) do { \
415
assert(coap_thread_pid == global_lock.pid); \
416
} while (0)
417
431
#define coap_lock_invert(c,alt_lock,failed) do { \
432
coap_lock_check_locked(c); \
433
coap_lock_unlock(c); \
434
alt_lock; \
435
coap_lock_lock(c,failed); \
436
} while (0)
437
438
extern
coap_lock_t
global_lock;
439
440
#else
/* ! COAP_THREAD_SAFE */
441
442
/*
443
* No locking - single thread
444
*/
445
typedef
coap_mutex_t
coap_lock_t
;
446
465
#define coap_lock_lock(c,failed)
466
477
#define coap_lock_unlock(c)
478
484
#define coap_lock_init()
485
491
#define coap_lock_check_locked(c) {}
492
505
#define coap_lock_callback(c,func) func
506
521
#define coap_lock_callback_ret(r,c,func) (r) = func
522
536
#define coap_lock_callback_release(c,func,failed) func
537
554
#define coap_lock_callback_ret_release(r,c,func,failed) (r) = func
555
571
#define coap_lock_invert(c,alt_lock,failed) func
572
573
#endif
/* ! COAP_THREAD_SAFE */
574
576
577
#endif
/* COAP_THREADSAFE_INTERNAL_H_ */
coap_mutex_t
int coap_mutex_t
Definition
coap_mutex_internal.h:141
coap_thread_pid_t
#define coap_thread_pid_t
Definition
coap_mutex_internal.h:148
coap_lock_t
coap_mutex_t coap_lock_t
Definition
coap_threadsafe_internal.h:445
include
coap3
coap_threadsafe_internal.h
Generated on
for libcoap by
1.17.0