Skip to content

Commit b2cf0f9

Browse files
committed
Use pthread TLD to store contexts
1 parent 905fd84 commit b2cf0f9

File tree

2 files changed

+96
-48
lines changed

2 files changed

+96
-48
lines changed

configure.ac

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,17 +135,9 @@ AC_CHECK_MEMBER([struct tm.tm_gmtoff], [AC_DEFINE([HAVE_TM_TM_GMT_OFF],1,[Define
135135
AC_CHECK_MEMBER([struct tm.__tm_gmtoff], [AC_DEFINE([HAVE_TM___TM_GMT_OFF],1,[Define to 1 if the system has the __tm_gmt_off field in struct tm])],
136136
[], [[#include <time.h>]])
137137

138-
AC_ARG_ENABLE([pthread-tls],
139-
[AC_HELP_STRING([--enable-pthread-tls],
140-
[Enable use of pthread thread local storage])],
141-
[],
142-
[enable_pthread_tls=no])
143-
144-
if test $enable_pthread_tls = yes; then
145-
AC_FIND_FUNC([pthread_key_create], [pthread], [#include <pthread.h>], [NULL, NULL])
146-
AC_FIND_FUNC([pthread_once], [pthread], [#include <pthread.h>], [NULL, NULL])
147-
AC_FIND_FUNC([atexit], [pthread], [#include <stdlib.h>], [NULL])
148-
fi
138+
AC_FIND_FUNC([pthread_key_create], [pthread], [#include <pthread.h>], [NULL, NULL])
139+
AC_FIND_FUNC([pthread_once], [pthread], [#include <pthread.h>], [NULL, NULL])
140+
AC_FIND_FUNC([atexit], [pthread], [#include <stdlib.h>], [NULL])
149141

150142
dnl libm math.h functions
151143
AC_CHECK_MATH_FUNC(acos)

src/jv_type_number.c

Lines changed: 93 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,94 @@ static decContext dec_context = {
5252
0, /*no clamping*/
5353
};
5454

55+
static decContext dec_context_to_double = {
56+
BIN64_DEC_PRECISION,
57+
DEC_MAX_EMAX,
58+
DEC_MIN_EMAX,
59+
DEC_ROUND_HALF_UP,
60+
0, /*no errors*/
61+
0, /*status*/
62+
0, /*no clamping*/
63+
};
64+
65+
#include <pthread.h>
66+
67+
static pthread_key_t dec_ctx_key;
68+
static pthread_key_t dec_ctx_dbl_key;
69+
static pthread_once_t dec_ctx_once = PTHREAD_ONCE_INIT;
70+
71+
#define DEC_CONTEXT tsd_dec_ctx_get(&dec_ctx_key)
72+
#define DEC_CONTEXT_TO_DOUBLE tsd_dec_ctx_get(&dec_ctx_dbl_key)
73+
74+
static void tsd_dec_ctx_init() {
75+
if (pthread_key_create(&dec_ctx_key, jv_mem_free) != 0) {
76+
fprintf(stderr, "error: cannot create thread specific key");
77+
abort();
78+
}
79+
decContext *ctx = calloc(1, sizeof(decContext));
80+
*ctx = dec_context;
81+
if (pthread_setspecific(dec_ctx_key, ctx) != 0) {
82+
fprintf(stderr, "error: cannot set thread specific data");
83+
abort();
84+
}
85+
86+
if (pthread_key_create(&dec_ctx_dbl_key, jv_mem_free) != 0) {
87+
fprintf(stderr, "error: cannot create thread specific key");
88+
abort();
89+
}
90+
ctx = calloc(1, sizeof(decContext));
91+
*ctx = dec_context_to_double;
92+
if (pthread_setspecific(dec_ctx_dbl_key, ctx) != 0) {
93+
fprintf(stderr, "error: cannot set thread specific data");
94+
abort();
95+
}
96+
}
97+
98+
static decContext* tsd_dec_ctx_get(pthread_key_t *key) {
99+
pthread_once(&dec_ctx_once, tsd_dec_ctx_init); // cannot fail
100+
return (decContext*)pthread_getspecific(*key);
101+
}
102+
103+
104+
static pthread_key_t dtoa_ctx_key;
105+
static pthread_once_t dtoa_ctx_once = PTHREAD_ONCE_INIT;
106+
107+
static struct dtoa_context *tsd_dtoa_context();
108+
109+
static void tsd_dtoa_ctx_dtor(void *ptr) {
110+
if (ptr) {
111+
jvp_dtoa_context_free((struct dtoa_context*)ptr);
112+
jv_mem_free(ptr);
113+
}
114+
}
115+
static void tsd_dtoa_ctx_fini() {
116+
struct dtoa_context *ctx = tsd_dtoa_context();
117+
tsd_dtoa_ctx_dtor(ctx);
118+
pthread_setspecific(dtoa_ctx_key, NULL);
119+
}
120+
121+
static void tsd_dtoa_ctx_init() {
122+
if (pthread_key_create(&dtoa_ctx_key, tsd_dtoa_ctx_fini) != 0) {
123+
fprintf(stderr, "error: cannot create thread specific key");
124+
abort();
125+
}
126+
atexit(tsd_dtoa_ctx_fini);
127+
}
128+
129+
static inline struct dtoa_context *tsd_dtoa_context() {
130+
pthread_once(&dtoa_ctx_once, tsd_dtoa_ctx_init); // cannot fail
131+
struct dtoa_context *ctx = (struct dtoa_context*)pthread_getspecific(dtoa_ctx_key);
132+
if (!ctx) {
133+
ctx = malloc(sizeof(struct dtoa_context));
134+
jvp_dtoa_context_init(ctx);
135+
if (pthread_setspecific(dtoa_ctx_key, ctx) != 0) {
136+
fprintf(stderr, "error: cannot set thread specific data");
137+
abort();
138+
}
139+
}
140+
return ctx;
141+
}
142+
55143
typedef struct {
56144
jv_refcnt refcnt;
57145
double num_double;
@@ -69,34 +157,6 @@ typedef struct {
69157
decNumberUnit units[BIN64_DEC_PRECISION];
70158
} decNumberDoublePrecision;
71159

72-
static decContext dec_context_to_double = {
73-
BIN64_DEC_PRECISION,
74-
DEC_MAX_EMAX,
75-
DEC_MIN_EMAX,
76-
DEC_ROUND_HALF_UP,
77-
0, /*no errors*/
78-
0, /*status*/
79-
0, /*no clamping*/
80-
};
81-
82-
static struct {
83-
uint64_t refcnt;
84-
struct dtoa_context C;
85-
} shared_dtoa_context;
86-
87-
static void jvp_number_dtoa_ctx_require() {
88-
if (shared_dtoa_context.refcnt == 0) {
89-
jvp_dtoa_context_init(&shared_dtoa_context.C);
90-
}
91-
shared_dtoa_context.refcnt ++;
92-
}
93-
94-
static void jvp_number_dtoa_ctx_release() {
95-
assert(shared_dtoa_context.refcnt > 0);
96-
if (--shared_dtoa_context.refcnt == 0) {
97-
jvp_dtoa_context_free(&shared_dtoa_context.C);
98-
}
99-
}
100160

101161
static inline int jvp_number_is_literal(jv n) {
102162
assert(JVP_HAS_KIND(n, JV_KIND_NUMBER));
@@ -130,15 +190,12 @@ static jv jvp_literal_number_new(const char * literal) {
130190

131191
jvp_literal_number * n = jvp_literal_number_alloc(strlen(literal));
132192

133-
// make sure that the dtoa context is somewhere around
134-
jvp_number_dtoa_ctx_require();
135-
136193
n->refcnt = JV_REFCNT_INIT;
137194
n->literal_data = NULL;
138-
decNumberFromString(&n->num_decimal, literal, &dec_context);
195+
decNumberFromString(&n->num_decimal, literal, DEC_CONTEXT);
139196
n->num_double = NAN;
140197

141-
if (dec_context.status & DEC_Conversion_syntax) {
198+
if (DEC_CONTEXT->status & DEC_Conversion_syntax) {
142199
jv_mem_free(n);
143200
return JV_INVALID;
144201
}
@@ -157,12 +214,12 @@ static double jvp_literal_number_to_double(jv j) {
157214
// reduce the number to the shortest possible form
158215
// while also making sure than no more than BIN64_DEC_PRECISION
159216
// digits are used (dec_context_to_double)
160-
decNumberReduce(&dec_double.number, p_dec_number, &dec_context_to_double);
217+
decNumberReduce(&dec_double.number, p_dec_number, DEC_CONTEXT_TO_DOUBLE);
161218

162219
decNumberToString(&dec_double.number, literal);
163220

164221
char *end;
165-
return jvp_strtod(&shared_dtoa_context.C, literal, &end);
222+
return jvp_strtod(tsd_dtoa_context(), literal, &end);
166223
}
167224

168225

@@ -219,7 +276,6 @@ const char* jv_number_get_literal(jv n) {
219276
void jvp_number_free(jv j) {
220277
assert(JVP_HAS_KIND(j, JV_KIND_NUMBER));
221278
if (JVP_HAS_FLAGS(j, JVP_FLAGS_NUMBER_LITERAL) && jvp_refcnt_dec(j.u.ptr)) {
222-
jvp_number_dtoa_ctx_release();
223279
jvp_literal_number* n = jvp_literal_number_ptr(j);
224280
if (n->literal_data) {
225281
jv_mem_free(n->literal_data);
@@ -286,7 +342,7 @@ int jvp_number_cmp(jv a, jv b) {
286342
decNumberCompare(&res.number,
287343
jvp_dec_number_ptr(a),
288344
jvp_dec_number_ptr(b),
289-
&dec_context
345+
DEC_CONTEXT
290346
);
291347
if (decNumberIsZero(&res.number)) {
292348
return 0;

0 commit comments

Comments
 (0)