NewMadeleine

Documentation

« back to PM2 home.
nm_core_types.h
Go to the documentation of this file.
1/*
2 * NewMadeleine
3 * Copyright (C) 2006-2026 (see AUTHORS file)
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or (at
8 * your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 */
15
22#ifndef NM_CORE_TYPES_H
23#define NM_CORE_TYPES_H
24
25#include <stdatomic.h>
26#include <inttypes.h>
27
28/* ** alignment ******************************************** */
29
30#define NM_ALIGN_FRONTIER sizeof(NM_ALIGN_TYPE)
31#define nm_aligned(x) nm_aligned_n((x), NM_ALIGN_FRONTIER)
32
34{
35 return (v + a - 1) & ~(a - 1);
36}
37
40static inline void*nm_aligned_ptr(const void*p, nm_len_t a)
41{
42 return (void*)((uintptr_t)p & ~((uintptr_t)a - 1));
43}
44
45/* ** Threads ********************************************* */
46
47#ifdef PIOMAN_MULTITHREAD
48#define NM_IS_THREADED 1
49#else
50#define NM_IS_THREADED ((nm_core_get_thread_level(nm_core_get_singleton()) >= NM_THREAD_SERIALIZED) ? 1 : 0)
51#endif
52
53/* ** Allocators ****************************************** */
54
55#define NM_ALLOCATOR_TYPE(ENAME, TYPE) PUK_ALLOCATOR_TYPE_EXT(ENAME, TYPE, !NM_IS_THREADED)
56
57/* ** Requests ********************************************* */
58
60
62
64NM_ALLOCATOR_TYPE(nm_req_chunk, struct nm_req_chunk_s);
65
66/* ** Tracks *********************************************** */
67
68#define NM_TRK_SMALL ((nm_trk_id_t)0)
69#define NM_TRK_LARGE ((nm_trk_id_t)1)
70#define NM_TRK_NONE ((nm_trk_id_t)-1)
71
73#define NM_MAX_TRACKS 2
74
75/* ** Sequence numbers ************************************* */
76
78#define NM_SEQ_FIRST ((nm_seq_t)1)
79
82{
84 seq++;
85 if(seq == NM_SEQ_NONE)
86 seq++;
87 return seq;
88}
89
92static inline int nm_seq_compare(nm_seq_t current, nm_seq_t seq1, nm_seq_t seq2)
93{
94 assert(seq1 != current);
95 assert(seq2 != current);
96 const nm_seq_t seq1_abs = (seq1 > current) ? (seq1 - current) : (seq1 - current - 1);
97 const nm_seq_t seq2_abs = (seq2 > current) ? (seq2 - current) : (seq2 - current - 1);
98 if(seq1_abs < seq2_abs)
99 return -1;
100 else if(seq1_abs > seq2_abs)
101 return 1;
102 else
103 return 0;
104}
105
109static inline int nm_seq_fuzzy_compare(nm_seq_t seq1, nm_seq_t seq2)
110{
111 static const nm_seq_t seq_compare_threshold = NM_SEQ_MAX / 4;
112 if(seq1 == seq2)
113 return 0;
114 else if((seq1 < seq2) && (seq2 - seq1 < seq_compare_threshold))
115 return -1;
116 else if((seq1 > seq2) && (seq1 - seq2 > 3 * seq_compare_threshold))
117 return -1;
118 else if((seq1 > seq2) && (seq1 - seq2 < seq_compare_threshold))
119 return 1;
120 else if((seq1 < seq2) && (seq2 - seq1 > 3 * seq_compare_threshold))
121 return 1;
122 else
123 {
124 NM_FATAL("cannot compare seq1 = %u; seq2=%u\n", seq1, seq2);
125 }
126}
127
128/* ** Profiling ******************************************** */
129
130#ifdef NMAD_PROFILE
131#define nm_profile_add(COUNTER, VALUE) do { __sync_fetch_and_add(&COUNTER, VALUE); } while(0)
132#else
133#define nm_profile_add(COUNTER, VALUE) do {} while(0)
134#endif
135
136#define nm_profile_inc(COUNTER) nm_profile_add(COUNTER, 1)
137#define nm_profile_dec(COUNTER) nm_profile_add(COUNTER, -1)
138
139
140/* ** Drivers ********************************************** */
141
142
143/* ** Events *********************************************** */
144
145PUK_VECT_TYPE(nm_core_monitor, struct nm_core_monitor_s*);
146
148PUK_LIST_TYPE(nm_core_pending_event,
149 struct nm_core_event_s event;
150 struct nm_core_monitor_s*p_core_monitor;
151 );
152
160PUK_LFQUEUE_TYPE(nm_core_dispatching_event, struct nm_core_dispatching_event_s*, NULL, 1024);
161NM_ALLOCATOR_TYPE(nm_core_dispatching_event, struct nm_core_dispatching_event_s);
162
163/* ** Unexpected chunks ************************************ */
164
165PUK_LIST_DECLARE_TYPE2(nm_unexpected_wildcard, struct nm_unexpected_s);
166PUK_LIST_DECLARE_TYPE2(nm_unexpected_gtag, struct nm_unexpected_s);
167PUK_LIST_DECLARE_TYPE2(nm_unexpected_gate, struct nm_unexpected_s);
168PUK_LIST_DECLARE_TYPE2(nm_unexpected_tag, struct nm_unexpected_s);
169
181
188
205
206PUK_LIST_CREATE_FUNCS(nm_unexpected_wildcard);
207PUK_LIST_CREATE_FUNCS(nm_unexpected_gtag);
208PUK_LIST_CREATE_FUNCS(nm_unexpected_gate);
209PUK_LIST_CREATE_FUNCS(nm_unexpected_tag);
210
211/* ** refcount ********************************************* */
212
214PUK_LIST_TYPE(nm_refcount_holder,
215 const void*p_holder;
216 const char*func;
217 const char*file;
218 int line;
219 );
220
226{
227 atomic_int refcount;
228#ifdef NMAD_DEBUG
229 char*object_id;
230 nm_spinlock_t lock;
231 struct nm_refcount_holder_list_s holders;
232#endif /* NMAD_DEBUG */
233};
234
235static inline void nm_refcount_dump(struct nm_refcount_s*p_refcount __attribute__((unused)))
236{
237#ifdef NMAD_DEBUG
238 nm_refcount_holder_itor_t i;
239 puk_list_foreach(nm_refcount_holder, i, &p_refcount->holders)
240 {
241 NM_WARN("pending ref- object = %s; p_holder = %p; %s:%d %s()\n",
242 p_refcount->object_id, i->p_holder, i->file, i->line, i->func);
243 }
244#endif /* NMAD_DEBUG */
245}
246
247static inline void nm_refcount_destroy(struct nm_refcount_s*p_refcount __attribute__((unused)))
248{
249#ifdef NMAD_DEBUG
250 nm_refcount_dump(p_refcount);
251 nm_spin_destroy(&p_refcount->lock);
252 padico_free(p_refcount->object_id);
253 nm_refcount_holder_list_destroy(&p_refcount->holders);
254#endif /* NMAD_DEBUG */
255}
256
257static inline int nm_refcount_get(struct nm_refcount_s*p_refcount)
258{
259 return atomic_load(&p_refcount->refcount);
260}
261
262#define nm_refcount_inc(REFCOUNT, HOLDER) \
263 nm_refcount_inc_internal(REFCOUNT, HOLDER, __FUNCTION__, __FILE__, __LINE__)
264
265#ifdef NMAD_DEBUG
266static inline void nm_refcount_add_holder(struct nm_refcount_s*p_refcount, const void*p_holder,
267 const char*func, const char*file, const int line)
268{
269 struct nm_refcount_holder_s*h = nm_refcount_holder_new();
270 h->p_holder = p_holder;
271 h->func = func;
272 h->file = file;
273 h->line = line;
274 nm_refcount_holder_list_push_back(&p_refcount->holders, h);
275}
276
277static inline int nm_refcount_count_holder(struct nm_refcount_s*p_refcount, const void*p_holder)
278{
279 int count = 0;
280 nm_refcount_holder_itor_t i;
281 puk_list_foreach(nm_refcount_holder, i, &p_refcount->holders)
282 {
283 if(i->p_holder == p_holder)
284 count++;
285 }
286 return count;
287}
288#endif /* NMAD_DEBUG */
289
290static inline void nm_refcount_inc_internal(struct nm_refcount_s*p_refcount, const void*p_holder __attribute__((unused)),
291 const char*func __attribute__((unused)),
292 const char*file __attribute__((unused)),
293 const int line __attribute__((unused)))
294{
295 assert(p_refcount->refcount >= 0);
296 atomic_fetch_add(&p_refcount->refcount, 1);
297#ifdef NMAD_DEBUG
298 if(p_holder != NULL)
299 {
300 nm_spin_lock(&p_refcount->lock);
301#if 0
302 if(nm_refcount_count_holder(p_refcount, p_holder) > 0)
303 {
304 nm_refcount_holder_itor_t i;
305 PUK_LIST_FIND(nm_refcount_holder, i, &p_refcount->holders, (i->p_holder == p_holder));
306 NM_WARN("p_holder = %p already holding a ref to p_refcount = %p (%s)\n"
307 " new holder: %s:%d %s()\n"
308 " previous holder: %s:%d %s()\n",
309 p_holder, p_refcount, p_refcount->object_id,
310 file, line, func, i->file, i->line, i->func);
311 }
312#endif /* 0 */
313 nm_refcount_add_holder(p_refcount, p_holder, func, file, line);
314 nm_spin_unlock(&p_refcount->lock);
315 }
316#endif /* NMAD_DEBUG */
317}
318
320static inline int nm_refcount_dec(struct nm_refcount_s*p_refcount, const void*p_holder __attribute__((unused)))
321{
322 const int nb_ref = atomic_fetch_sub(&p_refcount->refcount, 1) - 1;
323 assert(nb_ref >= 0);
324#ifdef NMAD_DEBUG
325 if(p_holder != NULL)
326 {
327 nm_spin_lock(&p_refcount->lock);
328 const int count = nm_refcount_count_holder(p_refcount, p_holder);
329 nm_refcount_holder_itor_t i;
330 PUK_LIST_FIND(nm_refcount_holder, i, &p_refcount->holders, (i->p_holder == p_holder));
331 if(i == NULL)
332 {
333 NM_FATAL("p_holder = %p not holding ref to p_refcount = %p (%s); cannot release\n",
334 p_holder, p_refcount, p_refcount->object_id);
335 }
336 else
337 {
338 nm_refcount_holder_list_remove(&p_refcount->holders, i);
339 nm_refcount_holder_delete(i);
340 }
341 assert(nm_refcount_count_holder(p_refcount, p_holder) == count - 1);
342 nm_spin_unlock(&p_refcount->lock);
343 }
344#endif /* NMAD_DEBUG */
345 return nb_ref;
346}
347
352static inline void nm_refcount_init(struct nm_refcount_s*p_refcount, char*p_object_id, const void*p_init_holder)
353{
354 atomic_store(&p_refcount->refcount, 1);
355#ifdef NMAD_DEBUG
356 p_refcount->object_id = p_object_id;
357 nm_spin_init(&p_refcount->lock);
358 nm_refcount_holder_list_init(&p_refcount->holders);
359 if(p_init_holder != NULL)
360 {
361 nm_refcount_add_holder(p_refcount, p_init_holder, __FUNCTION__, __FILE__, __LINE__);
362 }
363#else /* NMAD_DEBUG */
364 if(p_object_id != NULL)
365 padico_free(p_object_id); /* when not in debug, we won't use the object_id at all */
366#endif /* NMAD_DEBUG */
367}
368
369
370
371#endif /* NM_CORE_TYPES_H */
struct nm_core_event_s __attribute__
Definition nm_data.h:539
void(* nm_injector_pull_data_t)(struct nm_req_s *p_req, const struct nm_data_s *p_data, nm_len_t chunk_offset, nm_len_t chunk_len, void *p_ref)
user-supplied function called to pull data to posted request through nmad core p_req is the user requ...
static void nm_spin_init(nm_spinlock_t *p_spin)
init the spin lock
static void nm_spin_destroy(nm_spinlock_t *p_spin)
destroy the spin lock
static void nm_spin_lock(nm_spinlock_t *p_spin)
acquire the spin lock
static void nm_spin_unlock(nm_spinlock_t *p_spin)
release the spin lock
without even the implied warranty of !MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE See the GNU !General Public License for more details !mpif h
Definition mpif.h:19
PUK_LIST_DECLARE_TYPE2(nm_unexpected_wildcard, struct nm_unexpected_s)
static nm_len_t nm_aligned_n(nm_len_t v, nm_len_t a)
PUK_VECT_TYPE(nm_core_monitor, struct nm_core_monitor_s *)
static void nm_refcount_inc_internal(struct nm_refcount_s *p_refcount, const void *p_holder __attribute__((unused)), const char *func __attribute__((unused)), const char *file __attribute__((unused)), const int line __attribute__((unused)))
static nm_seq_t nm_seq_next(nm_seq_t seq)
Compute next sequence number.
PUK_LIST_CREATE_FUNCS(nm_req)
static void nm_refcount_init(struct nm_refcount_s *p_refcount, char *p_object_id, const void *p_init_holder)
initialize a new refcount object; get the object ID to make debugging easier; we take ownership of ob...
static int nm_seq_compare(nm_seq_t current, nm_seq_t seq1, nm_seq_t seq2)
compare to seq numbers, assuming they are in the future returns -1 if seq1 is before seq2,...
PUK_LFQUEUE_TYPE(nm_core_dispatching_event, struct nm_core_dispatching_event_s *, NULL, 1024)
#define NM_ALLOCATOR_TYPE(ENAME, TYPE)
static void * nm_aligned_ptr(const void *p, nm_len_t a)
get a pointer aligned to given alignment a
static int nm_seq_fuzzy_compare(nm_seq_t seq1, nm_seq_t seq2)
compare to seq numbers taking into account looping at overflow, assuming they are less than halftrip ...
static void nm_refcount_dump(struct nm_refcount_s *p_refcount __attribute__((unused)))
PUK_LIST_TYPE(nm_core_pending_event, struct nm_core_event_s event;struct nm_core_monitor_s *p_core_monitor;)
a pending event, not dispatched immediately because it was received out of order
static void nm_refcount_destroy(struct nm_refcount_s *p_refcount __attribute__((unused)))
static int nm_refcount_dec(struct nm_refcount_s *p_refcount, const void *p_holder __attribute__((unused)))
decrement refcount for holder; returns refcount (if 0, caller may free ref-counted resource)
static int nm_refcount_get(struct nm_refcount_s *p_refcount)
assert(p_data->ops.p_traversal !=NULL)
nm_seq_t seq
sequence number
Definition nm_headers.h:2
nm_mpi_count_t count
number of elements to be exchanged
#define NM_FATAL(format,...)
Definition nm_public.h:67
#define NM_WARN(format,...)
Definition nm_public.h:65
#define NM_SEQ_MAX
largest sequence number
Definition nm_types.h:114
#define NM_SEQ_NONE
Reserved sequence number never used by real packets.
Definition nm_types.h:111
int32_t nm_prio_t
message priority
Definition nm_types.h:78
uint64_t nm_len_t
data length used by nmad
Definition nm_types.h:68
uint32_t nm_seq_t
Sequence number for packets on a given gate/tag.
Definition nm_types.h:108
uint8_t nm_proto_t
protocol flags- not part of the public API, but needed for inline
Definition nm_types.h:105
a chunk to be injected into nmad core
nm_injector_pull_data_t p_pull_data
function to call to actually get data
void * p_ref
user-supplied ref for the above function
an event ready for dispatch (matching already done)
struct nm_monitor_s * p_monitor
struct nm_core_event_s event
An event, generated by the NewMad core.
global monitor for status transitions
An internal tag.
asynchronous tasks for nmad core.
Connection to another process.
Definition nm_gate.h:109
an incoming chunk of data
nm_seq_t seq
sequence number
nm_core_tag_t tag
full tag
nm_len_t chunk_offset
offset of the chunk in the full message
nm_proto_t flags
proto flags associated with the chunk (NM_PROTO_FLAG_*)
nm_prio_t priority
priority of the incoming data (only for rdv)
nm_len_t chunk_len
length of the chunk itself
nm_gate_t p_gate
gate the chunk arrived from
containers for matching info, used for caching
generic monitor, used for requests and for global events (with matching)
Internal packet wrapper.
a reference-counter that keeps trace of who increments/decrements in debug: full reference tracking i...
atomic_int refcount
the counter itself
a chunk of request
a generic pack/unpack request
a chunk of unexpected message to be stored
PUK_LIST_LINK(nm_unexpected_gate)
PUK_LIST_LINK(nm_unexpected_gtag)
link for list of unexpected per-tag
struct nm_core_task_s core_task
core task for unpack_next
struct nm_pkt_wrap_s * p_pw
pw this chunk arrived from; may be NULL if data is brought by injector
const union nm_header_generic_s * p_header
raw header in pw buffer
struct nm_matching_container_s matching
cache for matching containers
PUK_LIST_LINK(nm_unexpected_wildcard)
nm_len_t msg_len
length of full message on last chunk, NM_LEN_UNDEFINED if not last chunk
PUK_LIST_LINK(nm_unexpected_tag)
struct nm_chunk_injector_s injector
injector for this chunk
int matched
flag whether the unexpected is already matched (and delayed), and thus only enqueued in gtag matching...
struct nm_in_chunk_s chunk
metadata of the enclosed data chunk
a unified header for all types (ctrl/data)
Definition nm_headers.h:162