libcoap
4.3.5b
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-2025 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
124
void
coap_lock_unlock_func(
coap_lock_t
*lock,
const
char
*file,
int
line);
125
140
int
coap_lock_lock_func(
coap_lock_t
*lock,
const
char
*file,
int
line);
141
158
#define coap_lock_lock(c,failed) do { \
159
if (!coap_lock_lock_func(&global_lock, __FILE__, __LINE__)) { \
160
failed; \
161
} \
162
} while (0)
163
173
#define coap_lock_unlock(c) do { \
174
coap_lock_unlock_func(&global_lock, __FILE__, __LINE__); \
175
} while (0)
176
193
#define coap_lock_specific_lock(lock, failed) do { \
194
if (!coap_lock_lock_func(lock, __FILE__, __LINE__)) { \
195
failed; \
196
} \
197
} while (0)
198
209
#define coap_lock_specific_unlock(lock) do { \
210
coap_lock_unlock_func(lock, __FILE__, __LINE__); \
211
} while (0)
212
223
#define coap_lock_callback(c,func) do { \
224
coap_lock_check_locked(c); \
225
global_lock.in_callback++; \
226
global_lock.callback_file = __FILE__; \
227
global_lock.callback_line = __LINE__; \
228
func; \
229
global_lock.in_callback--; \
230
} while (0)
231
244
#define coap_lock_callback_ret(r,c,func) do { \
245
coap_lock_check_locked(c); \
246
global_lock.in_callback++; \
247
global_lock.callback_file = __FILE__; \
248
global_lock.callback_line = __LINE__; \
249
(r) = func; \
250
global_lock.in_callback--; \
251
} while (0)
252
264
#define coap_lock_callback_release(c,func,failed) do { \
265
coap_lock_check_locked(c); \
266
coap_lock_unlock(c); \
267
func; \
268
coap_lock_lock(c,failed); \
269
} while (0)
270
284
#define coap_lock_callback_ret_release(r,c,func,failed) do { \
285
coap_lock_check_locked(c); \
286
coap_lock_unlock(c); \
287
(r) = func; \
288
coap_lock_lock(c,failed); \
289
} while (0)
290
304
#define coap_lock_specific_callback_release(lock,func,failed) do { \
305
coap_lock_check_locked(NULL); \
306
coap_lock_unlock(NULL); \
307
coap_lock_specific_lock(lock, failed); \
308
(lock)->in_callback++; \
309
(lock)->callback_file = __FILE__; \
310
(lock)->callback_line = __LINE__; \
311
func; \
312
(lock)->in_callback--; \
313
coap_lock_specific_unlock(lock); \
314
coap_lock_lock(NULL, failed); \
315
} while (0)
316
317
extern
coap_lock_t
global_lock;
318
319
# else
/* ! COAP_THREAD_RECURSIVE_CHECK */
320
321
/*
322
* Locking, but no deadlock detection
323
*/
324
typedef
struct
coap_lock_t
{
325
coap_mutex_t
mutex;
326
coap_thread_pid_t
pid;
327
uint32_t in_callback;
328
volatile
uint32_t lock_count;
329
}
coap_lock_t
;
330
342
void
coap_lock_unlock_func(
coap_lock_t
*lock);
343
356
int
coap_lock_lock_func(
coap_lock_t
*lock);
357
374
#define coap_lock_lock(c,failed) do { \
375
if (!coap_lock_lock_func(&global_lock)) { \
376
failed; \
377
} \
378
} while (0)
379
396
#define coap_lock_specific_lock(lock, failed) do { \
397
if (!coap_lock_lock_func(lock)) { \
398
failed; \
399
} \
400
} while (0)
401
411
#define coap_lock_unlock(c) do { \
412
coap_lock_unlock_func(&global_lock); \
413
} while (0)
414
425
#define coap_lock_specific_unlock(lock) do { \
426
coap_lock_unlock_func(lock); \
427
} while (0)
428
439
#define coap_lock_callback(c,func) do { \
440
coap_lock_check_locked(c); \
441
global_lock.in_callback++; \
442
func; \
443
global_lock.in_callback--; \
444
} while (0)
445
458
#define coap_lock_callback_ret(r,c,func) do { \
459
coap_lock_check_locked(c); \
460
global_lock.in_callback++; \
461
(r) = func; \
462
global_lock.in_callback--; \
463
} while (0)
464
476
#define coap_lock_callback_release(c,func,failed) do { \
477
coap_lock_check_locked(c); \
478
coap_lock_unlock(c); \
479
func; \
480
coap_lock_lock(c,failed); \
481
} while (0)
482
496
#define coap_lock_specific_callback_release(lock,func,failed) do { \
497
coap_lock_check_locked(NULL); \
498
coap_lock_unlock(NULL); \
499
coap_lock_specific_lock(lock, failed); \
500
(lock)->in_callback++; \
501
func; \
502
(lock)->in_callback--; \
503
coap_lock_specific_unlock(lock); \
504
coap_lock_lock(NULL,failed); \
505
} while (0)
506
520
#define coap_lock_callback_ret_release(r,c,func,failed) do { \
521
coap_lock_check_locked(c); \
522
coap_lock_unlock(c); \
523
(r) = func; \
524
coap_lock_lock(c,failed); \
525
} while (0)
526
527
# endif
/* ! COAP_THREAD_RECURSIVE_CHECK */
528
532
#define coap_lock_init(lock) do { \
533
memset(&(lock)->mutex, 0, sizeof((lock)->mutex)); \
534
coap_mutex_init(&(lock)->mutex); \
535
} while (0)
536
540
#define coap_lock_check_locked(c) do { \
541
assert(coap_thread_pid == global_lock.pid); \
542
} while (0)
543
557
#define coap_lock_invert(c,alt_lock,failed) do { \
558
coap_lock_check_locked(c); \
559
coap_lock_unlock(c); \
560
alt_lock; \
561
coap_lock_lock(c,failed); \
562
} while (0)
563
564
extern
coap_lock_t
global_lock;
565
566
#else
/* ! COAP_THREAD_SAFE */
567
568
/*
569
* No locking - single thread
570
*/
571
typedef
coap_mutex_t
coap_lock_t
;
572
591
#define coap_lock_lock(c,failed)
592
611
#define coap_lock_specific_lock(lock,failed)
612
623
#define coap_lock_unlock(c)
624
635
#define coap_lock_specific_unlock(lock)
636
642
#define coap_lock_init(lock)
643
649
#define coap_lock_check_locked(c) {}
650
663
#define coap_lock_callback(c,func) func
664
679
#define coap_lock_callback_ret(r,c,func) (r) = func
680
694
#define coap_lock_callback_release(c,func,failed) func
695
706
#define coap_lock_specific_callback_release(lock,func,failed) func
707
724
#define coap_lock_callback_ret_release(r,c,func,failed) (r) = func
725
741
#define coap_lock_invert(c,alt_lock,failed) func
742
743
#endif
/* ! COAP_THREAD_SAFE */
744
746
747
#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:571
include
coap3
coap_threadsafe_internal.h
Generated on
for libcoap by
1.17.0