P99
p99_tp.h
Go to the documentation of this file.
1 /* This may look like nonsense, but it really is -*- mode: C; coding: utf-8 -*- */
2 /* */
3 /* Except for parts copied from previous work and as explicitly stated below, */
4 /* the author and copyright holder for this work is */
5 /* (C) copyright 2013-2014, 2018 Jens Gustedt, INRIA, France */
6 /* */
7 /* This file is free software; it is part of the P99 project. */
8 /* */
9 /* Licensed under the Apache License, Version 2.0 (the "License"); */
10 /* you may not use this file except in compliance with the License. */
11 /* You may obtain a copy of the License at */
12 /* */
13 /* http://www.apache.org/licenses/LICENSE-2.0 */
14 /* */
15 /* Unless required by applicable law or agreed to in writing, software */
16 /* distributed under the License is distributed on an "AS IS" BASIS, */
17 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
18 /* See the License for the specific language governing permissions and */
19 /* limitations under the License. */
20 /* */
21 #ifndef P99_RP_H
22 #define P99_RP_H 1
23 
24 #include "p99_enum.h"
25 #include "p99_generic.h"
26 
27 /* Additions by C11 */
28 # if __STDC_VERSION__ < 201100L
29 # include "p99_atomic.h"
30 # endif
31 
32 #ifdef P99_TP_NEED_INTEGER
33 # if UINTPTR_MAX == UINT32_MAX
34 typedef uint64_t p00_tp_glue;
35 # else
36 # if defined(UINT128_MAX)
37 typedef uint128_t p00_tp_glue;
38 # else
39 typedef p99x_uint128 p00_tp_glue;
40 # endif
41 # endif
42 
43 P99_CONSTANT(int, p00_tp_bits, sizeof(p00_tp_glue)*CHAR_BIT);
44 P99_CONSTANT(int, p00_tp_shift, p00_tp_bits/2);
45 
47 p00_tp_glue p00_tp_p2i(void * p, uintptr_t t) {
48  return (((p00_tp_glue)t)<<p00_tp_shift)|(uintptr_t)p;
49 }
50 
51 #define P00_TP_GLUE_INITIALIZER(VAL, TIC) ((((p00_tp_glue)VAL)<<p00_tp_shift)|((uintptr_t){(TIC)}))
52 
53 
55 void * p00_tp_i2p(p00_tp_glue v) {
56  return (void*)(uintptr_t)v;
57 }
58 
60 uintptr_t p00_tp_i2i(p00_tp_glue v) {
61  return v >> p00_tp_shift;
62 }
63 
64 #else
65 P99_DECLARE_STRUCT(p00_tp_glue);
66 
67 struct p00_tp_glue {
68  uintptr_t p00_tag;
69  void* p00_val;
70 };
71 
72 #define P00_TP_GLUE_INITIALIZER(VAL, TIC) { .p00_tag = (TIC), .p00_val = (VAL), }
73 
75 p00_tp_glue p00_tp_p2i(void * p00_val, uintptr_t p00_tag) {
76  return (p00_tp_glue) { .p00_tag = p00_tag, .p00_val = p00_val, };
77 }
78 
80 void * p00_tp_i2p(p00_tp_glue p00_sta) {
81  return p00_sta.p00_val;
82 }
83 
85 uintptr_t p00_tp_i2i(p00_tp_glue p00_sta) {
86  return p00_sta.p00_tag;
87 }
88 #endif
89 
90 P99_DECLARE_ATOMIC(p00_tp_glue);
91 
94 
95 
96 /* The tag part of a p99_tp ideally would be unique during the whole
97  run of a program instance. Since we might not have more than 32 bit
98  for this, this will not be possible in general, but we try to get
99  as close as possible to that.
100 
101  The problem should generally only arise for several accesses to the
102  same memory that are close in time. Particularly problematic are
103  such usages that go across free and re-malloc boundaries, because
104  two instances of p99_tp that are realized on the same address could
105  look the same if by coincidence their tags are the same.
106 
107  Therefore we compose each tag from two parts. One is a thread
108  specific counter (p00_tp_tick), and the other is a global counter
109  (p00_tp_tack) that is only consulted, when the thread counter
110  wraps.
111 
112  If uintptr_t is 64 bit wide this should be safe. Each of the type
113  of counters only would wrap after 4 billion increments. In
114  particular we only could have a duplicate tag after 4 billion
115  events that consist in the creation of a new thread or in
116  p00_tp_tick wrapping for certain threads.
117 
118  */
119 P99_DECLARE_THREAD_LOCAL(uintptr_t volatile, p00_tp_tick);
120 P99_WEAK(p00_tp_tack) _Atomic(uintptr_t) volatile p00_tp_tack;
121 
123 uintptr_t p00_tp_tick_get(void) {
124  enum { p00_bits = sizeof(uintptr_t)*CHAR_BIT/2, };
125  register uintptr_t const p00_mask = (UINTPTR_MAX >> p00_bits);
126  register uintptr_t volatile*const p00_ret = &P99_THREAD_LOCAL(p00_tp_tick);
127  if (P99_UNLIKELY(!(*p00_ret & p00_mask))) {
128  uintptr_t p00_tack = 0;
129  while (!p00_tack) {
130  p00_tack = atomic_fetch_add_explicit(&p00_tp_tack, 1u, memory_order_acq_rel);
131  p00_tack &= p00_mask;
132  }
133  *p00_ret = (p00_tack << p00_bits);
134  }
135  return ++(*p00_ret);
136 }
137 
139 p00_tp_glue volatile* p00_tp_glue_init(p00_tp_glue volatile* el, void * p) {
140  if (el) {
141  *el = (p00_tp_glue)P00_TP_GLUE_INITIALIZER(p, p00_tp_tick_get());
142  }
143  return el;
144 }
145 
155 struct p99_tp {
156  _Atomic(p00_tp_glue) volatile p00_val;
157  void*const p00_init;
158 };
159 
181 struct p99_tp_state {
182  p00_tp_glue p00_val;
183  p00_tp_glue p00_next;
184  p99_tp volatile* p00_tp;
185 };
186 
187 # define P00_TP_INITIALIZER(VAL) { \
188  .p00_val = ATOMIC_VAR_INIT(0), \
189  .p00_init = (VAL), \
190 }
191 
193 bool p00_tp_cmpxchg(_Atomic(p00_tp_glue) volatile*const p00_p, p00_tp_glue volatile*const p00_prev, p00_tp_glue p00_new) {
194  P99_MARK("wide cmpxchg start");
195  bool ret = atomic_compare_exchange_weak_explicit(p00_p, p00_prev, p00_new, memory_order_acq_rel, memory_order_consume);
196  P99_MARK("wide cmpxchg end");
197  return ret;
198 }
199 
201 p00_tp_glue p00_tp_get(register p99_tp volatile*const p00_tp) {
202  register p00_tp_glue p00_ret
203  = P99_LIKELY(p00_tp)
204  ? atomic_load_explicit(&p00_tp->p00_val, memory_order_consume)
205  : (p00_tp_glue)P00_TP_GLUE_INITIALIZER((void*)0, p00_tp_tick_get());
206  if (p00_tp && P99_UNLIKELY(!p00_tp_i2i(p00_ret))) {
207  /* Only store it in addressable memory if we can't avoid it. */
208  p00_tp_glue p00_ter = p00_ret;
209  register p00_tp_glue p00_rep = P00_TP_GLUE_INITIALIZER(p00_tp->p00_init, p00_tp_tick_get());
210  if (p00_tp_cmpxchg(&p00_tp->p00_val, &p00_ter, p00_rep))
211  p00_ret = p00_rep;
212  else
213  p00_ret = p00_ter;
214  }
215  return p00_ret;
216 }
217 
222 p00_tp_glue p99_tp_xchg(p99_tp volatile* p00_tp, void* p00_val) {
223  p00_tp_glue p00_ret
224  = P99_LIKELY(p00_tp)
225  ? atomic_load_explicit(&p00_tp->p00_val, memory_order_consume)
226  : (p00_tp_glue)P00_TP_GLUE_INITIALIZER((void*)0, p00_tp_tick_get());
227  if (P99_LIKELY(p00_tp)) {
228  register p00_tp_glue p00_rep = P00_TP_GLUE_INITIALIZER(p00_val, p00_tp_tick_get());
229  while (!p00_tp_cmpxchg(&p00_tp->p00_val, &p00_ret, p00_rep));
230  /* if this p99_tp has not been used before, return the value that
231  p99_tp_get would have returned. */
232  if (P99_UNLIKELY(!p00_tp_i2i(p00_ret))) {
233  p00_ret = (p00_tp_glue)P00_TP_GLUE_INITIALIZER(p00_tp->p00_init, p00_tp_tick_get());
234  }
235  }
236  return p00_ret;
237 }
238 
244 p99_tp_state p99_tp_state_initializer(register p99_tp volatile*const p00_tp, register void*const p00_p) {
245  return (p99_tp_state) {
246  .p00_val = p00_tp_get(p00_tp),
247  .p00_next = P00_TP_GLUE_INITIALIZER(p00_p, p00_tp_tick_get()),
248  .p00_tp = p00_tp,
249  };
250 }
251 
253 void * p99_tp_state_get(register p99_tp_state volatile*const p00_state) {
254  return P99_LIKELY(p00_state) ? p00_tp_i2p(p00_state->p00_val) : 0;
255 }
256 
258 void * p99_tp_get(register p99_tp volatile*const p00_tp) {
259  return p00_tp_i2p(p00_tp_get(p00_tp));
260 }
261 
263 void p99_tp_state_set(register p99_tp_state volatile*const p00_state, register void*const p00_p) {
264  if (P99_LIKELY(p00_state)) p00_state->p00_next = p00_tp_p2i(p00_p, p00_tp_i2i(p00_state->p00_next));
265 }
266 
268 bool p99_tp_state_commit(register p99_tp_state volatile*const p00_state) {
269  return P99_LIKELY(p00_state)
270  ? p00_tp_cmpxchg(&p00_state->p00_tp->p00_val, &p00_state->p00_val, p00_state->p00_next)
271  : false;
272 }
273 
275 bool p99_tp_state_check(register p99_tp_state volatile*const p00_state) {
276  return P99_LIKELY(p00_state)
277  ? p00_tp_cmpxchg(&p00_state->p00_tp->p00_val, &p00_state->p00_val, p00_state->p00_val)
278  : 0;
279 }
280 
281 # define P99_TP(T) P99_PASTE2(p00_tp_, T)
282 # define P99_TP_STATE(T) P99_PASTE2(p00_tp_glue_, T)
283 
284 P00_DOCUMENT_TYPE_ARGUMENT(P99_TP_DECLARE, 0)
285 # define P99_TP_DECLARE(T) \
286 typedef union P99_TP(T) P99_TP(T); \
287 typedef union P99_TP_STATE(T) P99_TP_STATE(T); \
288 union P99_TP(T) { \
289  p99_tp p00_tp; \
290  T p00_dum; /* we only need this for its type */ \
291  P99_TP_STATE(T)* p00_mud; /* we only need this for its type */ \
292  max_align_t p00_align; /* ensure maximal alignment */ \
293 }; \
294 union P99_TP_STATE(T) { \
295  p99_tp_state p00_st; \
296  T p00_dum; /* we only need this for its type */ \
297  P99_TP(T)* p00_mud; /* we only need this for its type */ \
298  max_align_t p00_align; /* ensure maximal alignment */ \
299 }
300 
301 # define P99_TP_TYPE(TP) __typeof__(*(TP)->p00_dum)
302 # define P99_TP_TYPE_STATE(TP) __typeof__(*(TP)->p00_mud)
303 # define P99_TP_STATE_TYPE(TPS) __typeof__(*(TPS)->p00_dum)
304 
305 
306 # define P99_TP_INITIALIZER(VAL) { .p00_tp = P00_TP_INITIALIZER(VAL), }
307 
309 void p00_tp_init(register p99_tp volatile*const p00_el, register void*const p00_val) {
310  if (P99_LIKELY(p00_el)) {
311  memset((void*)&p00_el->p00_val, 0, sizeof p00_el->p00_val);
312  atomic_init(&p00_el->p00_val, p00_tp_p2i(p00_val, p00_tp_tick_get()));
313  }
314 }
315 
316 # define p99_tp_init(EL, VAL) \
317 p99_extension ({ \
318  register __typeof__(EL) const p00_el = (EL); \
319  if (P99_LIKELY(p00_el)) p00_tp_init(&p00_el->p00_tp, (VAL)); \
320  p00_el; \
321  })
322 
331 #define P99_TP_STATE_INITIALIZER(TP, P) \
332 p99_extension ({ \
333  P99_MACRO_VAR(p00_tp, (TP)); \
334  /* ensure that P is assignment compatible to the */ \
335  /* base type, and that the return can't be used as lvalue */ \
336  register P99_TP_TYPE(p00_tp)* const p00_p = (P); \
337  register P99_TP_TYPE_STATE(p00_tp) const p00_r = { \
338  .p00_st = \
339  p00_tp \
340  ? p99_tp_state_initializer(&p00_tp->p00_tp, p00_p) \
341  : (p99_tp_state)P99_INIT, \
342  }; \
343  p00_r; \
344 })
345 
350 #define P99_TP_XCHG(TP, VAL) \
351 p99_extension ({ \
352  P99_MACRO_VAR(p00_tp, (TP)); \
353  /* ensure that the pointers that are converted to the */ \
354  /* base type, and that the return can't be used as lvalue */ \
355  register P99_TP_TYPE(p00_tp)* const p00_val = (VAL); \
356  register P99_TP_TYPE(p00_tp)* const p00_r \
357  = p00_tp ? p00_tp_i2p(p99_tp_xchg(&p00_tp->p00_tp, p00_val)) : 0; \
358  p00_r; \
359 })
360 
364 #define P99_TP_GET(TP) \
365 p99_extension ({ \
366  P99_MACRO_VAR(p00_tp, (TP)); \
367  /* ensure that pointer that is returned is converted to the */ \
368  /* base type, and that the return can't be used as lvalue */ \
369  register P99_TP_TYPE(p00_tp)* const p00_r \
370  = p00_tp ? p99_tp_get(&p00_tp->p00_tp) : 0; \
371  p00_r; \
372 })
373 
381 #define P99_TP_STATE_GET(TPS) \
382 p99_extension ({ \
383  P99_MACRO_VAR(p00_tps, (TPS)); \
384  /* ensure that pointer that is returned is converted to the */ \
385  /* base type, and that the return can't be used as lvalue */ \
386  register P99_TP_STATE_TYPE(p00_tps)* const p00_r \
387  = p00_tps ? p99_tp_state_get(&p00_tps->p00_st) : 0; \
388  p00_r; \
389 })
390 
391 
396 #define P99_TP_STATE_SET(TPS, P) \
397 do { \
398  P99_MACRO_VAR(p00_tps, (TPS)); \
399  /* ensure that P is assignment compatible to the */ \
400  /* base type. */ \
401  register P99_TP_STATE_TYPE(p00_tps)*const p00_p = (P); \
402  if (p00_tps) p99_tp_state_set(&p00_tps->p00_st, p00_p); \
403 } while (false)
404 
411 #define P99_TP_STATE_COMMIT(TPS) \
412 p99_extension ({ \
413  P99_MACRO_VAR(p00_tps, (TPS)); \
414  register bool const p00_r \
415  = p00_tps ? p99_tp_state_commit(&p00_tps->p00_st) : false; \
416  p00_r; \
417 })
418 
426 #define P99_TP_STATE_CHECK(TPS) \
427 p99_extension ({ \
428  P99_MACRO_VAR(p00_tps, (TPS)); \
429  register bool const p00_r \
430  = p00_tps ? p99_tp_state_check(&(p00_tps)->p00_st) : false; \
431  p00_r; \
432  })
433 
434 
435 #define P99_REF_ACCOUNT(REF) \
436 p99_extension ({ \
437  P99_MACRO_VAR(p00_ref, (REF)); \
438  /* ensure that the pointer is converted to the */ \
439  /* base type, and that the return can't be used as lvalue */ \
440  register __typeof__(p00_ref) const p00_r = p00_ref; \
441  if (p00_r) atomic_fetch_add_explicit(&p00_r->p99_cnt, 1, memory_order_acq_rel); \
442  p00_r; \
443 })
444 
445 #define P99_TP_REF_ACCOUNT(TP, REF) \
446 p99_extension ({ \
447  P99_MACRO_VAR(p00_tp, (TP)); \
448  /* ensure that pointer that is returned is converted to the */ \
449  /* base type, and that the return can't be used as lvalue */ \
450  register P99_TP_TYPE(p00_tp)* const p00_r = (REF); \
451  if (p00_r) atomic_fetch_add_explicit(&p00_r->p99_cnt, 1, memory_order_acq_rel); \
452  p00_r; \
453 })
454 
455 #define P99_REF_DISCOUNT(REF, DELETE) \
456 p99_extension ({ \
457  P99_MACRO_VAR(p00_ref, (REF)); \
458  register void (*const p00_d)(__typeof__(*p00_ref) const*) \
459  = (DELETE); \
460  /* ensure that the pointer is converted to the */ \
461  /* base type, and that the return can't be used as lvalue */ \
462  register __typeof__(*p00_ref)*const p00_r = p00_ref; \
463  if (p00_r && (atomic_fetch_sub_explicit(&p00_r->p99_cnt, 1, memory_order_acq_rel) == 1)) \
464  p00_d(p00_r); \
465  p00_r; \
466 })
467 
468 #define P99_TP_REF_INITIALIZER(VAL, ACCOUNT) P99_TP_INITIALIZER(P99_GENERIC_NULLPTR_CONSTANT(VAL, (void*)0, ACCOUNT(VAL)))
469 
470 #define P00_TP_REF_INIT2(TP, VAL) \
471 p99_extension ({ \
472  P99_MACRO_VAR(p00_tp, (TP)); \
473  /* ensure that pointer that is returned is converted to the */ \
474  /* base type, and that the return can't be used as lvalue */ \
475  register P99_TP_TYPE(p00_tp)* const p00_val = (VAL); \
476  p99_tp_init(p00_tp, P99_REF_ACCOUNT(p00_val)); \
477 })
478 
479 
480 #define P00_TP_REF_INIT1(TP) p99_tp_init(TP, 0)
481 
482 #define P99_TP_REF_INIT(...) \
483 P99_IF_LT(P99_NARG(__VA_ARGS__), 2) \
484 (P00_TP_REF_INIT1(__VA_ARGS__)) \
485 (P00_TP_REF_INIT2(__VA_ARGS__))
486 
487 #define P99_TP_REF_REPLACE(TP, SP, DELETE) \
488 P99_REF_DISCOUNT(P99_TP_XCHG((TP), P99_REF_ACCOUNT(SP)), (DELETE))
489 
490 #define P99_TP_REF_MV(TP, SP, DELETE) \
491 P99_REF_DISCOUNT(P99_TP_XCHG((TP), P99_TP_XCHG((SP), 0)), (DELETE))
492 
493 #define P99_TP_REF_DESTROY(TP, DELETE) \
494 (void)P99_REF_DISCOUNT(P99_TP_XCHG((TP), 0), (DELETE))
495 
496 
531 P00_DOCUMENT_TYPE_ARGUMENT(P99_TP_REF_DECLARE, 0)
532 #ifdef P00_DOXYGEN
533 #define P99_TP_REF_DECLARE(T) \
534 typedef struct T ## _ref T ## _ref; \
535  \
536  \
537  \
538 struct T ## _ref { \
539  T* p00_ref; \
540 }
541 #else
542 #define P99_TP_REF_DECLARE(T) \
543 P99_POINTER_TYPE(T); \
544 P99_TP_DECLARE(P99_PASTE2(T, _ptr)); \
545  \
546 typedef P99_TP(P99_PASTE2(T, _ptr)) P99_PASTE2(T, _ref)
547 #endif
548 
549 P00_DOCUMENT_TYPE_ARGUMENT(P99_TP_REF_DEFINE, 0)
550 #define P99_TP_REF_DEFINE(T) \
551 P99_INSTANTIATE(T*, P99_PASTE2(T, _account), T*); \
552 P99_INSTANTIATE(T*, P99_PASTE2(T, _discount), T*); \
553 P99_INSTANTIATE(P99_PASTE2(T, _ref)*, P99_PASTE2(T, _ref_init), P99_PASTE2(T, _ref)*, T*); \
554 P99_INSTANTIATE(T*, P99_PASTE2(T, _ref_init_defarg_1), void); \
555 P99_INSTANTIATE(T*, P99_PASTE2(T, _ref_get), P99_PASTE2(T, _ref) volatile*); \
556 P99_INSTANTIATE(T*, P99_PASTE2(T, _ref_replace), P99_PASTE2(T, _ref) volatile*, T*); \
557 P99_INSTANTIATE(T*, P99_PASTE2(T, _ref_mv), P99_PASTE2(T, _ref) volatile*, \
558  P99_PASTE2(T, _ref) volatile*); \
559 P99_INSTANTIATE(T*, P99_PASTE2(T, _ref_assign), P99_PASTE2(T, _ref) volatile*, \
560  P99_PASTE2(T, _ref) volatile*); \
561 P99_INSTANTIATE(void, P99_PASTE2(T, _ref_destroy), P99_PASTE2(T, _ref)*)
562 
563 #ifdef P00_DOXYGEN
564 P00_DOCUMENT_TYPE_ARGUMENT(P99_TP_REF_FUNCTIONS, 0)
565 #define P99_TP_REF_FUNCTIONS(T) \
566  \
567  \
568 inline T* P99_PASTE2(T, _account)(T*){} \
569  \
570  \
571  \
572 inline T* P99_PASTE2(T, _discount)(T*){} \
573  \
574  \
575  \
576 inline P99_PASTE2(T, _ref)* P99_PASTE2(T, _ref_init)(P99_PASTE2(T, _ref)*, T*){} \
577  \
578  \
579  \
580 inline T* P99_PASTE2(T, _ref_init_defarg_1)(void){} \
581  \
582  \
583  \
584 inline T* P99_PASTE2(T, _ref_get)(P99_PASTE2(T, _ref) volatile*){} \
585  \
586  \
587  \
588 inline T* P99_PASTE2(T, _ref_replace)(P99_PASTE2(T, _ref) volatile*, T*){} \
589  \
590  \
591  \
592  \
593 inline T* P99_PASTE2(T, _ref_mv)(P99_PASTE2(T, _ref) volatile*, \
594  P99_PASTE2(T, _ref) volatile*){} \
595  \
596  \
597  \
598  \
599 inline T* P99_PASTE2(T, _ref_assign)(P99_PASTE2(T, _ref) volatile*, \
600  P99_PASTE2(T, _ref) volatile*){} \
601  \
602  \
603  \
604 inline void P99_PASTE2(T, _ref_destroy)(P99_PASTE2(T, _ref)*) {} \
605 P99_MACRO_END(P99_TP_REF_FUNCTIONS)
606 
607 #else
608 P00_DOCUMENT_TYPE_ARGUMENT(P99_TP_REF_FUNCTIONS, 0)
609 #define P99_TP_REF_FUNCTIONS(T) \
610  \
611  inline \
612  T* \
613  P99_PASTE2(T, _account)(T* p00_el) { \
614  return P99_REF_ACCOUNT(p00_el); \
615  } \
616  \
617  inline \
618  T* \
619  P99_PASTE2(T, _discount)(T* p00_el) { \
620  return P99_REF_DISCOUNT(p00_el, P99_PASTE2(T, _delete)); \
621  } \
622  \
623  inline \
624  P99_PASTE2(T, _ref)* P99_PASTE2(T, _ref_init)(P99_PASTE2(T, _ref)* el, T* p00_v) { \
625  return P99_TP_REF_INIT(el, p00_v); \
626  } \
627  \
628  inline \
629  T* P99_PASTE2(T, _ref_init_defarg_1)(void) { \
630  return 0; \
631  } \
632  \
633  inline \
634  T* P99_PASTE2(T, _ref_get)(P99_PASTE2(T, _ref) volatile* p00_ref) { \
635  return P99_TP_GET(p00_ref); \
636  } \
637  \
638  inline \
639  T* P99_PASTE2(T, _ref_replace)(P99_PASTE2(T, _ref) volatile* p00_tar, T* p00_sou) { \
640  return P99_TP_REF_REPLACE(p00_tar, p00_sou, P99_PASTE2(T, _delete)); \
641  } \
642  \
643  inline \
644  T* P99_PASTE2(T, _ref_mv)(P99_PASTE2(T, _ref) volatile* p00_tar, \
645  P99_PASTE2(T, _ref) volatile* p00_sou) { \
646  return P99_TP_REF_MV(p00_tar, p00_sou, P99_PASTE2(T, _delete)); \
647  } \
648  \
649  inline \
650  T* P99_PASTE2(T, _ref_assign)(P99_PASTE2(T, _ref) volatile* p00_tar, \
651  P99_PASTE2(T, _ref) volatile* p00_sou) { \
652  return P99_TP_REF_REPLACE(p00_tar, P99_TP_GET(p00_sou), P99_PASTE2(T, _delete)); \
653  } \
654  \
655  inline \
656  void P99_PASTE2(T, _ref_destroy)(P99_PASTE2(T, _ref)* p00_ref) { \
657  P99_TP_REF_DESTROY(p00_ref, P99_PASTE2(T, _delete)); \
658  } \
659  \
660 P99_MACRO_END(P99_TP_REF_FUNCTIONS)
661 
662 #endif
663 
664 
665 #endif
void
void void
Definition: p99_bitset.h:84
P99_LIKELY
#define P99_LIKELY(...)
Mark the conditional expression as being likely.
Definition: p99_compiler.h:1010
P99_DECLARE_ATOMIC
#define P99_DECLARE_ATOMIC(...)
Definition: p99_atomic.h:56
P99_THREAD_LOCAL
#define P99_THREAD_LOCAL
P99_CONSTANT
#define P99_CONSTANT(T, NAME, INIT)
define a compile time constant NAME of type T with value INIT
Definition: p99_enum.h:258
P99_TP_REF_FUNCTIONS
#define P99_TP_REF_FUNCTIONS(T)
p
P00_CLAUSE2 p(P00_WEAK1(p00_cb))(P00_WEAK2(p00_cb)) pp99_callback_stack p00_at_quick_exit
P99_TP_DECLARE
#define P99_TP_DECLARE(T)
p99_tp
struct p99_tp p99_tp
Definition: p99_tp.h:92
p99_tp_state
struct p99_tp_state p99_tp_state
Definition: p99_tp.h:93
p99_inline
#define p99_inline
Try to force a function always to be inlined.
Definition: p99_compiler.h:496
P99_WEAK
#define P99_WEAK(...)
Declare a symbol to be weak such that it can be provided several times without error.
Definition: p99_compiler.h:561
P99_DECLARE_STRUCT
#define P99_DECLARE_STRUCT(NAME)
forward declaration of a struct NAME
Definition: p99_type.h:59
P99_MARK
#define P99_MARK(X)
mark the produced assembler with a comment that contains the source line number and the token X
Definition: p99_block.h:95
p99_enum.h
p99_atomic.h
v
P00_CLAUSE2 v(_Pragma("weak exit_handler_s"))(_Pragma("weak exit_handler_s
P99_TP_REF_DECLARE
#define P99_TP_REF_DECLARE(T)
P99_DECLARE_THREAD_LOCAL
P99_DECLARE_THREAD_LOCAL(uintptr_t volatile, p00_tp_tick)
p99_generic.h
P99_UNLIKELY
#define P99_UNLIKELY(...)
Mark the conditional expression as being unlikely.
Definition: p99_compiler.h:994
P99_TP_REF_DEFINE
#define P99_TP_REF_DEFINE(T)
p99x_uint128
extendedInt p99x_uint128
An unsigned integer type of width 128 that exceeds the C99 specifications.
Definition: p99_int.h:149