P99
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
p99_clib.h
Go to the documentation of this file.
00001 /* This may look like nonsense, but it really is -*- mode: C -*-             */
00002 /*                                                                           */
00003 /* Except of parts copied from previous work and as explicitly stated below, */
00004 /* the author and copyright holder for this work is                          */
00005 /* (C) copyright  2012 Jens Gustedt, INRIA, France                           */
00006 /*                                                                           */
00007 /* This file is free software; it is part of the P99 project.                */
00008 /* You can redistribute it and/or modify it under the terms of the QPL as    */
00009 /* given in the file LICENSE. It is distributed without any warranty;        */
00010 /* without even the implied warranty of merchantability or fitness for a     */
00011 /* particular purpose.                                                       */
00012 /*                                                                           */
00013 #ifndef P99_CLIB_H
00014 #define P99_CLIB_H 1
00015 
00016 #include "p99_for.h"
00017 #include "p99_new.h"
00018 
00019 /* Additions by C11 */
00020 # if __STDC_VERSION__ < 201100L
00021 
00022 # include "p99_atomic.h"
00023 
00024 /* Provide aligned allocation. */
00025 
00026 # if (_XOPEN_SOURCE >= 600) || defined(P00_DOXYGEN)
00027 
00034 #define p00_has_feature_aligned_alloc 1
00035 #define p00_has_extension_aligned_alloc 1
00036 #define p00_has_feature_quick_exit 1
00037 #define p00_has_extension_quick_exit 1
00038 #if defined(P99_LIFO_POP) || defined(P00_DOXYGEN)
00039 # define p00_has_feature_quick_exit_thread_safe 1
00040 # define p00_has_extension_quick_exit_thread_safe 1
00041 #endif
00042 
00048 p99_inline
00049 void *aligned_alloc(size_t p00_alignment, size_t p00_size) {
00050   void * p00_ret = 0;
00051   int err = posix_memalign(&p00_ret, p00_alignment, p00_size);
00052   /* If there was an error and a fake pointer has been returned, free
00053      this pointer and set it to 0. This is the only way to return an
00054      error for this C11 interface. */
00055   if (err && p00_ret) {
00056     free(p00_ret);
00057     p00_ret = 0;
00058   }
00059   return p00_ret;
00060 }
00061 
00062 typedef struct p00_aqe_el p00_aqe_el;
00063 P99_POINTER_TYPE(p00_aqe_el);
00064 #ifndef P00_DOXYGEN
00065 # if p99_has_feature(quick_exit_thread_safe)
00066 P99_DECLARE_ATOMIC(p00_aqe_el_ptr);
00067 typedef _Atomic(p00_aqe_el_ptr) p00_aqe_list;
00068 # else
00069 typedef p00_aqe_el_ptr p00_aqe_list;
00070 # endif
00071 #endif
00072 
00073 typedef void p00_aqe_func(void);
00074 
00075 struct p00_aqe_el {
00076   p00_aqe_el_ptr p99_lifo;
00077   p00_aqe_func * p00_func;
00078 };
00079 
00080 
00081 p99_inline
00082 p00_aqe_el* p00_aqe_el_init(p00_aqe_el * p00_obj, p00_aqe_func* p00_func) {
00083   if (p00_obj) {
00084     *p00_obj = (p00_aqe_el) { .p00_func = p00_func };
00085   }
00086   return p00_obj;
00087 }
00088 
00089 p99_inline
00090 p00_aqe_el* p00_at_quick_exit_top(p00_aqe_list* p00_l) {
00091 #if p99_has_feature(quick_exit_thread_safe)
00092   return P99_LIFO_TOP(p00_l);
00093 #else
00094   return *p00_l;
00095 #endif
00096 }
00097 
00098 p99_inline
00099 void p00_at_quick_exit_push(p00_aqe_list* p00_l, p00_aqe_el* p00_el) {
00100 #if p99_has_feature(quick_exit_thread_safe)
00101   P99_LIFO_PUSH(p00_l, p00_el);
00102 #else
00103   p00_el->p99_lifo = *p00_l;
00104   *p00_l = p00_el;
00105 #endif
00106 }
00107 
00108 p99_inline
00109 p00_aqe_el* p00_at_quick_exit_pop(p00_aqe_list* p00_l) {
00110 #if p99_has_feature(quick_exit_thread_safe)
00111   return P99_LIFO_POP(p00_l);
00112 #else
00113   p00_aqe_el *p00_el = p00_at_quick_exit_top(p00_l);
00114   if (p00_el) {
00115     *p00_l = p00_el->p99_lifo;
00116     p00_el->p99_lifo = 0;
00117   }
00118   return p00_el;
00119 #endif
00120 }
00121 
00122 /* In both cases this is guaranteed to do the correct
00123    initialization. */
00124 P99_WEAK(p00_aqe)
00125 p00_aqe_list p00_at_quick_exit;
00126 
00127 p99_inline
00128 int at_quick_exit(void (*p00_func)(void)) {
00129   int ret = 0;
00130   p00_aqe_el *el = P99_NEW(p00_aqe_el, p00_func);
00131   ret = !el;
00132   if (P99_LIKELY(!ret)) p00_at_quick_exit_push(&p00_at_quick_exit, el);
00133   return ret;
00134 }
00135 
00136 p99_inline
00137 _Noreturn void quick_exit(int status) {
00138   for (;;) {
00139     p00_aqe_el *el = p00_at_quick_exit_pop(&p00_at_quick_exit);
00140     if (P99_UNLIKELY(!el)) break;
00141     p00_aqe_func * p00_func = el->p00_func;
00142     free(el);
00143     p00_func();
00144   }
00145   _Exit(status);
00146 }
00147 
00148 P99_WEAK(p00_at_thrd_exit)
00149 p99_tss p00_at_thrd_exit;
00150 
00151 #define P00_AT_THRD_EXIT                                              \
00152 (*(p00_aqe_list*)p00_thread_local_get(&(p00_at_thrd_exit), sizeof(p00_aqe_list*)))
00153 
00154 P99_SETJMP_INLINE(p00_run_at_thrd_exit)
00155 void p00_run_at_thrd_exit(void * li) {
00156   p00_aqe_list* list = li;
00157   for (;;) {
00158     p00_aqe_el *el = p00_at_quick_exit_pop(list);
00159     if (P99_UNLIKELY(!el)) break;
00160     p00_aqe_func * p00_func = el->p00_func;
00161     free(el);
00162     p00_func();
00163   }
00164 }
00165 
00166 p99_tss p00_at_thrd_exit = { .p00_func = p00_run_at_thrd_exit, };
00167 
00168 
00176 p99_inline
00177 int at_thrd_exit(void (*p00_func)(void)) {
00178   int ret = 0;
00179   p00_aqe_el *el = P99_NEW(p00_aqe_el, p00_func);
00180   ret = !el;
00181   if (P99_LIKELY(!ret)) p00_at_quick_exit_push(&P00_AT_THRD_EXIT, el);
00182   return ret;
00183 }
00184 
00189 #  endif /* XOPEN */
00190 # endif /* STDC < 2011 */
00191 #endif
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Defines