Line | Count | Source |
1 | | #include <assert.h> |
2 | | #include <stdio.h> |
3 | | #include <stdlib.h> |
4 | | #include <string.h> |
5 | | #include "jv.h" |
6 | | |
7 | | struct nomem_handler { |
8 | | jv_nomem_handler_f handler; |
9 | | void *data; |
10 | | }; |
11 | | |
12 | | #if !defined(HAVE_PTHREAD_KEY_CREATE) || \ |
13 | | !defined(HAVE_PTHREAD_ONCE) || \ |
14 | | !defined(HAVE_ATEXIT) |
15 | | |
16 | | /* Try thread-local storage? */ |
17 | | |
18 | | #ifdef _MSC_VER |
19 | | /* Visual C++: yes */ |
20 | | static __declspec(thread) struct nomem_handler nomem_handler; |
21 | | #define USE_TLS |
22 | | #else |
23 | | #ifdef HAVE___THREAD |
24 | | /* GCC and friends: yes */ |
25 | | static __thread struct nomem_handler nomem_handler; |
26 | | #define USE_TLS |
27 | | #endif /* HAVE___THREAD */ |
28 | | #endif /* _MSC_VER */ |
29 | | |
30 | | #endif /* !HAVE_PTHREAD_KEY_CREATE */ |
31 | | |
32 | | #ifdef USE_TLS |
33 | | void jv_nomem_handler(jv_nomem_handler_f handler, void *data) { |
34 | | nomem_handler.handler = handler; |
35 | | } |
36 | | |
37 | | static void memory_exhausted(void) { |
38 | | if (nomem_handler.handler) |
39 | | nomem_handler.handler(nomem_handler.data); // Maybe handler() will longjmp() to safety |
40 | | // Or not |
41 | | fprintf(stderr, "jq: error: cannot allocate memory\n"); |
42 | | abort(); |
43 | | } |
44 | | #else /* USE_TLS */ |
45 | | |
46 | | #ifdef HAVE_PTHREAD_KEY_CREATE |
47 | | #include <pthread.h> |
48 | | |
49 | | static pthread_key_t nomem_handler_key; |
50 | | static pthread_once_t mem_once = PTHREAD_ONCE_INIT; |
51 | | |
52 | | /* tsd_fini is called on application exit */ |
53 | | /* it clears the nomem_handler allocated in the main thread */ |
54 | 0 | static void tsd_fini(void) { |
55 | 0 | struct nomem_handler *nomem_handler; |
56 | 0 | nomem_handler = pthread_getspecific(nomem_handler_key); |
57 | 0 | if (nomem_handler) { |
58 | 0 | (void) pthread_setspecific(nomem_handler_key, NULL); |
59 | 0 | free(nomem_handler); |
60 | 0 | } |
61 | 0 | } |
62 | | |
63 | | /* The tsd_fini_thread is a destructor set by calling */ |
64 | | /* pthread_key_create(&nomem_handler_key, tsd_fini_thread) */ |
65 | | /* It is called when thread ends */ |
66 | 0 | static void tsd_fini_thread(void *nomem_handler) { |
67 | 0 | free(nomem_handler); |
68 | 0 | } |
69 | | |
70 | 0 | static void tsd_init(void) { |
71 | 0 | if (pthread_key_create(&nomem_handler_key, tsd_fini_thread) != 0) { |
72 | 0 | fprintf(stderr, "jq: error: cannot create thread specific key"); |
73 | 0 | abort(); |
74 | 0 | } |
75 | 0 | if (atexit(tsd_fini) != 0) { |
76 | 0 | fprintf(stderr, "jq: error: cannot set an exit handler"); |
77 | 0 | abort(); |
78 | 0 | } |
79 | 0 | } |
80 | | |
81 | | static void tsd_init_nomem_handler(void) |
82 | 0 | { |
83 | 0 | if (pthread_getspecific(nomem_handler_key) == NULL) { |
84 | 0 | struct nomem_handler *nomem_handler = calloc(1, sizeof(struct nomem_handler)); |
85 | 0 | if (pthread_setspecific(nomem_handler_key, nomem_handler) != 0) { |
86 | 0 | fprintf(stderr, "jq: error: cannot set thread specific data"); |
87 | 0 | abort(); |
88 | 0 | } |
89 | 0 | } |
90 | 0 | } |
91 | | |
92 | 0 | void jv_nomem_handler(jv_nomem_handler_f handler, void *data) { |
93 | 0 | pthread_once(&mem_once, tsd_init); // cannot fail |
94 | 0 | tsd_init_nomem_handler(); |
95 | |
|
96 | 0 | struct nomem_handler *nomem_handler; |
97 | |
|
98 | 0 | nomem_handler = pthread_getspecific(nomem_handler_key); |
99 | 0 | if (nomem_handler == NULL) { |
100 | 0 | handler(data); |
101 | 0 | fprintf(stderr, "jq: error: cannot allocate memory\n"); |
102 | 0 | abort(); |
103 | 0 | } |
104 | 0 | nomem_handler->handler = handler; |
105 | 0 | nomem_handler->data = data; |
106 | 0 | } |
107 | | |
108 | 0 | static void memory_exhausted(void) { |
109 | 0 | struct nomem_handler *nomem_handler; |
110 | |
|
111 | 0 | pthread_once(&mem_once, tsd_init); |
112 | 0 | tsd_init_nomem_handler(); |
113 | |
|
114 | 0 | nomem_handler = pthread_getspecific(nomem_handler_key); |
115 | 0 | if (nomem_handler && nomem_handler->handler) |
116 | 0 | nomem_handler->handler(nomem_handler->data); // Maybe handler() will longjmp() to safety |
117 | | // Or not |
118 | 0 | fprintf(stderr, "jq: error: cannot allocate memory\n"); |
119 | 0 | abort(); |
120 | 0 | } |
121 | | |
122 | | #else |
123 | | |
124 | | /* No thread-local storage of any kind that we know how to handle */ |
125 | | |
126 | | static struct nomem_handler nomem_handler; |
127 | | void jv_nomem_handler(jv_nomem_handler_f handler, void *data) { |
128 | | nomem_handler.handler = handler; |
129 | | nomem_handler.data = data; |
130 | | } |
131 | | |
132 | | static void memory_exhausted(void) { |
133 | | fprintf(stderr, "jq: error: cannot allocate memory\n"); |
134 | | abort(); |
135 | | } |
136 | | |
137 | | #endif /* HAVE_PTHREAD_KEY_CREATE */ |
138 | | #endif /* USE_TLS */ |
139 | | |
140 | | |
141 | 5.36M | void* jv_mem_alloc(size_t sz) { |
142 | 5.36M | void* p = malloc(sz); |
143 | 5.36M | if (!p) { |
144 | 0 | memory_exhausted(); |
145 | 0 | } |
146 | 5.36M | return p; |
147 | 5.36M | } |
148 | | |
149 | 0 | void* jv_mem_alloc_unguarded(size_t sz) { |
150 | 0 | return malloc(sz); |
151 | 0 | } |
152 | | |
153 | 0 | void* jv_mem_calloc(size_t nemb, size_t sz) { |
154 | 0 | assert(nemb > 0 && sz > 0); |
155 | 0 | void* p = calloc(nemb, sz); |
156 | 0 | if (!p) { |
157 | 0 | memory_exhausted(); |
158 | 0 | } |
159 | 0 | return p; |
160 | 0 | } |
161 | | |
162 | 0 | void* jv_mem_calloc_unguarded(size_t nemb, size_t sz) { |
163 | 0 | assert(nemb > 0 && sz > 0); |
164 | 0 | return calloc(nemb, sz); |
165 | 0 | } |
166 | | |
167 | 0 | char* jv_mem_strdup(const char *s) { |
168 | 0 | char *p = strdup(s); |
169 | 0 | if (!p) { |
170 | 0 | memory_exhausted(); |
171 | 0 | } |
172 | 0 | return p; |
173 | 0 | } |
174 | | |
175 | 0 | char* jv_mem_strdup_unguarded(const char *s) { |
176 | 0 | return strdup(s); |
177 | 0 | } |
178 | | |
179 | 5.36M | void jv_mem_free(void* p) { |
180 | 5.36M | free(p); |
181 | 5.36M | } |
182 | | |
183 | 7.27k | void* jv_mem_realloc(void* p, size_t sz) { |
184 | 7.27k | p = realloc(p, sz); |
185 | 7.27k | if (!p) { |
186 | 0 | memory_exhausted(); |
187 | 0 | } |
188 | 7.27k | return p; |
189 | 7.27k | } |