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
27/* ** alignment ******************************************** */
28
29#define NM_ALIGN_FRONTIER sizeof(NM_ALIGN_TYPE)
30#define nm_aligned(x) nm_aligned_n((x), NM_ALIGN_FRONTIER)
31
33{
34 return (v + a - 1) & ~(a - 1);
35}
36
39static inline void*nm_aligned_ptr(const void*p, nm_len_t a)
40{
41 return (void*)((uintptr_t)p & ~(a - 1));
42}
43
44#define nm_offset_of(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
45#define nm_container_of(ptr, type, member) \
46 ((type *)((char *)(__typeof__ (&((type *)0)->member))(ptr)- \
47 nm_offset_of(type,member)))
48
49/* ** Threads ********************************************* */
50
51#ifdef PIOMAN_MULTITHREAD
52#define NM_IS_THREADED 1
53#else
54#define NM_IS_THREADED ((nm_core_get_thread_level(nm_core_get_singleton()) >= NM_THREAD_SERIALIZED) ? 1 : 0)
55#endif
56
57/* ** Allocators ****************************************** */
58
59#define NM_ALLOCATOR_TYPE(ENAME, TYPE) PUK_ALLOCATOR_TYPE_EXT(ENAME, TYPE, !NM_IS_THREADED)
60
61/* ** Requests ********************************************* */
62
64
66
68NM_ALLOCATOR_TYPE(nm_req_chunk, struct nm_req_chunk_s);
69
70/* ** Tracks *********************************************** */
71
72#define NM_TRK_SMALL ((nm_trk_id_t)0)
73#define NM_TRK_LARGE ((nm_trk_id_t)1)
74#define NM_TRK_NONE ((nm_trk_id_t)-1)
75
77#define NM_MAX_TRACKS 2
78
79/* ** Sequence numbers ************************************* */
80
82#define NM_SEQ_FIRST ((nm_seq_t)1)
83
86{
88 seq++;
89 if(seq == NM_SEQ_NONE)
90 seq++;
91 return seq;
92}
93
96static inline int nm_seq_compare(nm_seq_t current, nm_seq_t seq1, nm_seq_t seq2)
97{
98 assert(seq1 != current);
99 assert(seq2 != current);
100 const nm_seq_t seq1_abs = (seq1 > current) ? (seq1 - current) : (seq1 - current - 1);
101 const nm_seq_t seq2_abs = (seq2 > current) ? (seq2 - current) : (seq2 - current - 1);
102 if(seq1_abs < seq2_abs)
103 return -1;
104 else if(seq1_abs > seq2_abs)
105 return 1;
106 else
107 return 0;
108}
109
113static inline int nm_seq_fuzzy_compare(nm_seq_t seq1, nm_seq_t seq2)
114{
115 static const nm_seq_t seq_compare_threshold = NM_SEQ_MAX / 4;
116 if(seq1 == seq2)
117 return 0;
118 else if((seq1 < seq2) && (seq2 - seq1 < seq_compare_threshold))
119 return -1;
120 else if((seq1 > seq2) && (seq1 - seq2 > 3 * seq_compare_threshold))
121 return -1;
122 else if((seq1 > seq2) && (seq1 - seq2 < seq_compare_threshold))
123 return 1;
124 else if((seq1 < seq2) && (seq2 - seq1 > 3 * seq_compare_threshold))
125 return 1;
126 else
127 {
128 NM_FATAL("cannot compare seq1 = %u; seq2=%u\n", seq1, seq2);
129 }
130}
131
132/* ** Profiling ******************************************** */
133
134#ifdef NMAD_PROFILE
135#define nm_profile_add(COUNTER, VALUE) do { __sync_fetch_and_add(&COUNTER, VALUE); } while(0)
136#else
137#define nm_profile_add(COUNTER, VALUE) do {} while(0)
138#endif
139
140#define nm_profile_inc(COUNTER) nm_profile_add(COUNTER, 1)
141
142/* ** init helper ****************************************** */
143
149
150#define NM_LAZY_INITIALIZER_INIT { .init_done = 0, .initializing = 0 }
151
157#define NM_LAZY_INITIALIZER(ENAME, CTOR, DTOR) \
158 static struct nm_lazy_initializer_s ENAME ## _lazy_initializer = NM_LAZY_INITIALIZER_INIT; \
159 \
160 static void ENAME ## _lazy_init(void) \
161 { \
162 if(ENAME##_lazy_initializer.init_done == 0) \
163 { \
164 if(nm_atomic_inc(&ENAME##_lazy_initializer.initializing) == 0) \
165 { \
166 (*CTOR)(); \
167 nm_atomic_inc(&ENAME##_lazy_initializer.init_done); \
168 } \
169 else \
170 { \
171 while(!ENAME##_lazy_initializer.init_done) \
172 { \
173 sched_yield(); \
174 } \
175 } \
176 } \
177 else if(ENAME##_lazy_initializer.init_done == -1) \
178 { \
179 NM_FATAL("trying to use %s after detructor.\n", #ENAME); \
180 } \
181 } \
182 static void ENAME ## _lazy_destructor(void) __attribute__((destructor)); \
183 static void ENAME ## _lazy_destructor(void) \
184 { \
185 if(ENAME##_lazy_initializer.init_done > 0) \
186 { \
187 (*DTOR)(); \
188 } \
189 ENAME##_lazy_initializer.init_done = -1; \
190 }
191
192
193/* ** Drivers ********************************************** */
194
195
196/* ** Events *********************************************** */
197
198PUK_VECT_TYPE(nm_core_monitor, struct nm_core_monitor_s*);
199
201PUK_LIST_TYPE(nm_core_pending_event,
202 struct nm_core_event_s event;
203 struct nm_core_monitor_s*p_core_monitor;
204 );
205
213PUK_LFQUEUE_TYPE(nm_core_dispatching_event, struct nm_core_dispatching_event_s*, NULL, 1024);
214NM_ALLOCATOR_TYPE(nm_core_dispatching_event, struct nm_core_dispatching_event_s);
215
216/* ** Unexpected chunks ************************************ */
217
218PUK_LIST_DECLARE_TYPE2(nm_unexpected_wildcard, struct nm_unexpected_s);
219PUK_LIST_DECLARE_TYPE2(nm_unexpected_gtag, struct nm_unexpected_s);
220PUK_LIST_DECLARE_TYPE2(nm_unexpected_gate, struct nm_unexpected_s);
221PUK_LIST_DECLARE_TYPE2(nm_unexpected_tag, struct nm_unexpected_s);
222
234
241
258
259PUK_LIST_CREATE_FUNCS(nm_unexpected_wildcard);
260PUK_LIST_CREATE_FUNCS(nm_unexpected_gtag);
261PUK_LIST_CREATE_FUNCS(nm_unexpected_gate);
262PUK_LIST_CREATE_FUNCS(nm_unexpected_tag);
263
264/* ** refcount ********************************************* */
265
267PUK_LIST_TYPE(nm_refcount_holder,
268 const void*p_holder;
269 const char*func;
270 const char*file;
271 int line;
272 );
273
279{
280 atomic_int refcount;
281#ifdef NMAD_DEBUG
282 char*object_id;
283 nm_spinlock_t lock;
284 struct nm_refcount_holder_list_s holders;
285#endif /* NMAD_DEBUG */
286};
287
288static inline void nm_refcount_dump(struct nm_refcount_s*p_refcount __attribute__((unused)))
289{
290#ifdef NMAD_DEBUG
291 nm_refcount_holder_itor_t i;
292 puk_list_foreach(nm_refcount_holder, i, &p_refcount->holders)
293 {
294 NM_WARN("pending ref- object = %s; p_holder = %p; %s:%d %s()\n",
295 p_refcount->object_id, i->p_holder, i->file, i->line, i->func);
296 }
297#endif /* NMAD_DEBUG */
298}
299
300static inline void nm_refcount_destroy(struct nm_refcount_s*p_refcount __attribute__((unused)))
301{
302#ifdef NMAD_DEBUG
303 nm_refcount_dump(p_refcount);
304 nm_spin_destroy(&p_refcount->lock);
305 padico_free(p_refcount->object_id);
306 nm_refcount_holder_list_destroy(&p_refcount->holders);
307#endif /* NMAD_DEBUG */
308}
309
310static inline int nm_refcount_get(struct nm_refcount_s*p_refcount)
311{
312 return atomic_load(&p_refcount->refcount);
313}
314
315#define nm_refcount_inc(REFCOUNT, HOLDER) \
316 nm_refcount_inc_internal(REFCOUNT, HOLDER, __FUNCTION__, __FILE__, __LINE__)
317
318#ifdef NMAD_DEBUG
319static inline void nm_refcount_add_holder(struct nm_refcount_s*p_refcount, const void*p_holder,
320 const char*func, const char*file, const int line)
321{
322 struct nm_refcount_holder_s*h = nm_refcount_holder_new();
323 h->p_holder = p_holder;
324 h->func = func;
325 h->file = file;
326 h->line = line;
327 nm_refcount_holder_list_push_back(&p_refcount->holders, h);
328}
329
330static inline int nm_refcount_count_holder(struct nm_refcount_s*p_refcount, const void*p_holder)
331{
332 int count = 0;
333 nm_refcount_holder_itor_t i;
334 puk_list_foreach(nm_refcount_holder, i, &p_refcount->holders)
335 {
336 if(i->p_holder == p_holder)
337 count++;
338 }
339 return count;
340}
341#endif /* NMAD_DEBUG */
342
343static inline void nm_refcount_inc_internal(struct nm_refcount_s*p_refcount, const void*p_holder __attribute__((unused)),
344 const char*func __attribute__((unused)),
345 const char*file __attribute__((unused)),
346 const int line __attribute__((unused)))
347{
348 assert(p_refcount->refcount >= 0);
349 atomic_fetch_add(&p_refcount->refcount, 1);
350#ifdef NMAD_DEBUG
351 if(p_holder != NULL)
352 {
353 nm_spin_lock(&p_refcount->lock);
354#if 0
355 if(nm_refcount_count_holder(p_refcount, p_holder) > 0)
356 {
357 nm_refcount_holder_itor_t i;
358 PUK_LIST_FIND(nm_refcount_holder, i, &p_refcount->holders, (i->p_holder == p_holder));
359 NM_WARN("p_holder = %p already holding a ref to p_refcount = %p (%s)\n"
360 " new holder: %s:%d %s()\n"
361 " previous holder: %s:%d %s()\n",
362 p_holder, p_refcount, p_refcount->object_id,
363 file, line, func, i->file, i->line, i->func);
364 }
365#endif /* 0 */
366 nm_refcount_add_holder(p_refcount, p_holder, func, file, line);
367 nm_spin_unlock(&p_refcount->lock);
368 }
369#endif /* NMAD_DEBUG */
370}
371
373static inline int nm_refcount_dec(struct nm_refcount_s*p_refcount, const void*p_holder __attribute__((unused)))
374{
375 const int nb_ref = atomic_fetch_sub(&p_refcount->refcount, 1) - 1;
376 assert(nb_ref >= 0);
377#ifdef NMAD_DEBUG
378 if(p_holder != NULL)
379 {
380 nm_spin_lock(&p_refcount->lock);
381 const int count = nm_refcount_count_holder(p_refcount, p_holder);
382 nm_refcount_holder_itor_t i;
383 PUK_LIST_FIND(nm_refcount_holder, i, &p_refcount->holders, (i->p_holder == p_holder));
384 if(i == NULL)
385 {
386 NM_FATAL("p_holder = %p not holding ref to p_refcount = %p (%s); cannot release\n",
387 p_holder, p_refcount, p_refcount->object_id);
388 }
389 else
390 {
391 nm_refcount_holder_list_remove(&p_refcount->holders, i);
392 nm_refcount_holder_delete(i);
393 }
394 assert(nm_refcount_count_holder(p_refcount, p_holder) == count - 1);
395 nm_spin_unlock(&p_refcount->lock);
396 }
397#endif /* NMAD_DEBUG */
398 return nb_ref;
399}
400
405static inline void nm_refcount_init(struct nm_refcount_s*p_refcount, char*p_object_id, const void*p_init_holder)
406{
407 atomic_store(&p_refcount->refcount, 1);
408#ifdef NMAD_DEBUG
409 p_refcount->object_id = p_object_id;
410 nm_spin_init(&p_refcount->lock);
411 nm_refcount_holder_list_init(&p_refcount->holders);
412 if(p_init_holder != NULL)
413 {
414 nm_refcount_add_holder(p_refcount, p_init_holder, __FUNCTION__, __FILE__, __LINE__);
415 }
416#else /* NMAD_DEBUG */
417 if(p_object_id != NULL)
418 padico_free(p_object_id); /* when not in debug, we won't use the object_id at all */
419#endif /* NMAD_DEBUG */
420}
421
422
423
424#endif /* NM_CORE_TYPES_H */
struct nm_core_event_s __attribute__
Definition nm_data.h:538
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
#define NM_FATAL(format,...)
Definition nm_log.h:36
#define NM_WARN(format,...)
Definition nm_log.h:34
nm_mpi_count_t count
number of elements to be exchanged
#define NM_SEQ_MAX
largest sequence number
Definition nm_types.h:108
#define NM_SEQ_NONE
Reserved sequence number never used by real packets.
Definition nm_types.h:105
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:102
uint8_t nm_proto_t
protocol flags- not part of the public API, but needed for inline
Definition nm_types.h:99
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:104
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
int initializing
whether init is in progress
int init_done
whether init is already done
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