iodine 0.7.43 → 0.7.46
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- data/.gitignore +1 -0
- data/CHANGELOG.md +18 -0
- data/examples/etag.ru +16 -0
- data/ext/iodine/extconf.rb +21 -16
- data/ext/iodine/fio.c +1108 -162
- data/ext/iodine/fio.h +49 -13
- data/ext/iodine/fio_cli.c +1 -1
- data/ext/iodine/fio_tls_missing.c +8 -0
- data/ext/iodine/fio_tls_openssl.c +8 -0
- data/ext/iodine/fio_tmpfile.h +13 -1
- data/ext/iodine/fiobj_data.c +6 -4
- data/ext/iodine/fiobj_data.h +2 -1
- data/ext/iodine/fiobj_hash.c +32 -6
- data/ext/iodine/fiobj_mustache.c +9 -0
- data/ext/iodine/fiobj_numbers.c +86 -8
- data/ext/iodine/fiobj_str.c +24 -11
- data/ext/iodine/fiobject.c +1 -1
- data/ext/iodine/fiobject.h +5 -3
- data/ext/iodine/http.c +75 -32
- data/ext/iodine/http1.c +2 -1
- data/ext/iodine/http1_parser.h +1065 -103
- data/ext/iodine/http_internal.c +1 -0
- data/ext/iodine/http_internal.h +4 -2
- data/ext/iodine/iodine.c +64 -1
- data/ext/iodine/iodine.h +2 -0
- data/ext/iodine/iodine_caller.c +48 -8
- data/ext/iodine/iodine_connection.c +4 -0
- data/ext/iodine/iodine_http.c +28 -2
- data/ext/iodine/iodine_rack_io.c +15 -2
- data/ext/iodine/iodine_tcp.c +14 -0
- data/ext/iodine/iodine_tls.c +8 -0
- data/ext/iodine/mustache_parser.h +4 -0
- data/ext/iodine/redis_engine.c +14 -11
- data/ext/iodine/websockets.c +7 -3
- data/iodine.gemspec +5 -4
- data/lib/iodine/version.rb +1 -1
- metadata +15 -13
data/ext/iodine/fio.h
CHANGED
@@ -215,8 +215,15 @@ Version and helper macros
|
|
215
215
|
|
216
216
|
#include <fcntl.h>
|
217
217
|
#include <sys/stat.h>
|
218
|
+
#ifndef __MINGW32__
|
218
219
|
#include <sys/time.h>
|
220
|
+
#endif
|
219
221
|
#include <unistd.h>
|
222
|
+
#ifdef __MINGW32__
|
223
|
+
#include <winsock2.h>
|
224
|
+
#include <winsock.h>
|
225
|
+
#include <ws2tcpip.h>
|
226
|
+
#endif
|
220
227
|
|
221
228
|
#if !defined(__GNUC__) && !defined(__clang__) && !defined(FIO_GNUC_BYPASS)
|
222
229
|
#define __attribute__(...)
|
@@ -243,6 +250,25 @@ Version and helper macros
|
|
243
250
|
#include <sys/socket.h>
|
244
251
|
#endif
|
245
252
|
|
253
|
+
#ifdef __MINGW32__
|
254
|
+
#define __S_IFMT 0170000
|
255
|
+
#define __S_IFLNK 0120000
|
256
|
+
#define __S_ISTYPE(mode, mask) (((mode) & __S_IFMT) == (mask))
|
257
|
+
#define S_ISLNK(mode) __S_ISTYPE((mode), __S_IFLNK)
|
258
|
+
|
259
|
+
#define SIGKILL 9
|
260
|
+
#define SIGTERM 15
|
261
|
+
#define SIGCONT 17
|
262
|
+
|
263
|
+
#define pipe(fds) _pipe(fds, 65536, _O_BINARY)
|
264
|
+
|
265
|
+
int fork(void);
|
266
|
+
int kill(int, int);
|
267
|
+
ssize_t pread(int, void*, size_t, off_t);
|
268
|
+
ssize_t pwrite(int, const void *, size_t, off_t);
|
269
|
+
int fio_osffd4fd(unsigned int);
|
270
|
+
#endif
|
271
|
+
|
246
272
|
/* *****************************************************************************
|
247
273
|
Patch for OSX version < 10.12 from https://stackoverflow.com/a/9781275/4025095
|
248
274
|
***************************************************************************** */
|
@@ -2068,7 +2094,7 @@ FIO_FUNC inline int fio_trylock(fio_lock_i *lock);
|
|
2068
2094
|
/**
|
2069
2095
|
* Releases a spinlock. Releasing an unacquired lock will break it.
|
2070
2096
|
*
|
2071
|
-
* Returns a non-zero value on success, or 0 if the lock was in an
|
2097
|
+
* Returns a non-zero value on success, or 0 if the lock was in an unlocked
|
2072
2098
|
* state.
|
2073
2099
|
*/
|
2074
2100
|
FIO_FUNC inline int fio_unlock(fio_lock_i *lock);
|
@@ -2539,8 +2565,9 @@ FIO_FUNC inline uint64_t fio_risky_hash(const void *data_, size_t len,
|
|
2539
2565
|
uint64_t result = fio_lrot64(v0, 17) + fio_lrot64(v1, 13) +
|
2540
2566
|
fio_lrot64(v2, 47) + fio_lrot64(v3, 57);
|
2541
2567
|
|
2542
|
-
|
2543
|
-
|
2568
|
+
uint64_t len64 = len;
|
2569
|
+
len64 ^= (len64 << 33);
|
2570
|
+
result += len64;
|
2544
2571
|
|
2545
2572
|
result += v0 * RISKY_PRIME_1;
|
2546
2573
|
result ^= fio_lrot64(result, 13);
|
@@ -2931,9 +2958,9 @@ C++ extern end
|
|
2931
2958
|
/**
|
2932
2959
|
* The logarithmic value for a memory block, 15 == 32Kb, 16 == 64Kb, etc'
|
2933
2960
|
*
|
2934
|
-
* By default, a block of memory is 32Kb
|
2961
|
+
* By default, a block of memory is a 32Kb slice from an 8Mb allocation.
|
2935
2962
|
*
|
2936
|
-
* A value of 16 will make this a 64Kb
|
2963
|
+
* A value of 16 will make this a 64Kb slice from a 16Mb allocation.
|
2937
2964
|
*/
|
2938
2965
|
#define FIO_MEMORY_BLOCK_SIZE_LOG (15)
|
2939
2966
|
#endif
|
@@ -3000,7 +3027,7 @@ FIO_FUNC inline int fio_trylock(fio_lock_i *lock) {
|
|
3000
3027
|
/**
|
3001
3028
|
* Releases a spinlock. Releasing an unacquired lock will break it.
|
3002
3029
|
*
|
3003
|
-
* Returns a non-zero value on success, or 0 if the lock was in an
|
3030
|
+
* Returns a non-zero value on success, or 0 if the lock was in an unlocked
|
3004
3031
|
* state.
|
3005
3032
|
*/
|
3006
3033
|
FIO_FUNC inline int fio_unlock(fio_lock_i *lock) {
|
@@ -3864,6 +3891,7 @@ FIO_FUNC char *fio_str_detach(fio_str_s *s) {
|
|
3864
3891
|
}
|
3865
3892
|
/* make a copy */
|
3866
3893
|
void *tmp = FIO_MALLOC(i.len + 1);
|
3894
|
+
FIO_ASSERT_ALLOC(tmp);
|
3867
3895
|
memcpy(tmp, i.data, i.len + 1);
|
3868
3896
|
i.data = tmp;
|
3869
3897
|
} else {
|
@@ -3874,6 +3902,7 @@ FIO_FUNC char *fio_str_detach(fio_str_s *s) {
|
|
3874
3902
|
} else if (s->dealloc != FIO_FREE) {
|
3875
3903
|
/* make a copy */
|
3876
3904
|
void *tmp = FIO_MALLOC(i.len + 1);
|
3905
|
+
FIO_ASSERT_ALLOC(tmp);
|
3877
3906
|
memcpy(tmp, i.data, i.len + 1);
|
3878
3907
|
i.data = tmp;
|
3879
3908
|
if (s->dealloc)
|
@@ -4338,7 +4367,7 @@ inline FIO_FUNC fio_str_info_s fio_str_write_i(fio_str_s *s, int64_t num) {
|
|
4338
4367
|
fio_str_info_s i;
|
4339
4368
|
if (!num)
|
4340
4369
|
goto zero;
|
4341
|
-
char buf[22];
|
4370
|
+
char buf[22] = {0};
|
4342
4371
|
uint64_t l = 0;
|
4343
4372
|
uint8_t neg;
|
4344
4373
|
if ((neg = (num < 0))) {
|
@@ -4472,7 +4501,7 @@ FIO_FUNC fio_str_info_s fio_str_readfile(fio_str_s *s, const char *filename,
|
|
4472
4501
|
intptr_t start_at, intptr_t limit) {
|
4473
4502
|
fio_str_info_s state = {.data = NULL};
|
4474
4503
|
#if defined(__unix__) || defined(__linux__) || defined(__APPLE__) || \
|
4475
|
-
defined(__CYGWIN__)
|
4504
|
+
defined(__CYGWIN__) || defined(__MINGW32__)
|
4476
4505
|
/* POSIX implementations. */
|
4477
4506
|
if (filename == NULL || !s)
|
4478
4507
|
return state;
|
@@ -4502,7 +4531,7 @@ FIO_FUNC fio_str_info_s fio_str_readfile(fio_str_s *s, const char *filename,
|
|
4502
4531
|
}
|
4503
4532
|
}
|
4504
4533
|
|
4505
|
-
if (stat(filename, &f_data)) {
|
4534
|
+
if (stat(filename, &f_data) == -1) {
|
4506
4535
|
goto finish;
|
4507
4536
|
}
|
4508
4537
|
|
@@ -4510,9 +4539,12 @@ FIO_FUNC fio_str_info_s fio_str_readfile(fio_str_s *s, const char *filename,
|
|
4510
4539
|
state = fio_str_info(s);
|
4511
4540
|
goto finish;
|
4512
4541
|
}
|
4513
|
-
|
4542
|
+
#ifdef __MINGW32__
|
4543
|
+
file = _open(filename, O_RDONLY);
|
4544
|
+
#else
|
4514
4545
|
file = open(filename, O_RDONLY);
|
4515
|
-
|
4546
|
+
#endif
|
4547
|
+
if (file == -1)
|
4516
4548
|
goto finish;
|
4517
4549
|
|
4518
4550
|
if (start_at < 0) {
|
@@ -4531,7 +4563,11 @@ FIO_FUNC fio_str_info_s fio_str_readfile(fio_str_s *s, const char *filename,
|
|
4531
4563
|
state.data = NULL;
|
4532
4564
|
state.len = state.capa = 0;
|
4533
4565
|
}
|
4566
|
+
#ifdef __MINGW32__
|
4567
|
+
_close(file);
|
4568
|
+
#else
|
4534
4569
|
close(file);
|
4570
|
+
#endif
|
4535
4571
|
finish:
|
4536
4572
|
FIO_FREE(path);
|
4537
4573
|
return state;
|
@@ -6012,7 +6048,7 @@ FIO_NAME(_insert_or_overwrite_)(FIO_NAME(s) * set, FIO_SET_HASH_TYPE hash_value,
|
|
6012
6048
|
pos->hash = hash_value;
|
6013
6049
|
pos->pos->hash = hash_value;
|
6014
6050
|
FIO_SET_COPY(pos->pos->obj, obj);
|
6015
|
-
|
6051
|
+
|
6016
6052
|
return pos->pos->obj;
|
6017
6053
|
}
|
6018
6054
|
|
@@ -6282,7 +6318,7 @@ restart:
|
|
6282
6318
|
FIO_LOG_FATAL(
|
6283
6319
|
"facil.io Set / Hash Map has too many collisions (%zu/%zu)."
|
6284
6320
|
"\n\t\tthis is a fatal implementation error,"
|
6285
|
-
"please report this issue at
|
6321
|
+
"please report this issue at facil.io's open source project"
|
6286
6322
|
"\n\t\tNote: hash maps and sets should never reach this point."
|
6287
6323
|
"\n\t\tThey should be guarded against collision attacks.",
|
6288
6324
|
set->pos, set->capa);
|
data/ext/iodine/fio_cli.c
CHANGED
@@ -50,7 +50,7 @@ typedef struct {
|
|
50
50
|
#define AVOID_MACRO
|
51
51
|
|
52
52
|
#define FIO_CLI_HASH_VAL(s) \
|
53
|
-
fio_risky_hash((s).data, (s).len, (
|
53
|
+
fio_risky_hash((s).data, (s).len, (uintptr_t)fio_cli_start)
|
54
54
|
|
55
55
|
/* *****************************************************************************
|
56
56
|
CLI Parsing
|
@@ -4,6 +4,13 @@ License: MIT
|
|
4
4
|
|
5
5
|
Feel free to copy, use and enjoy according to the license provided.
|
6
6
|
*/
|
7
|
+
#ifdef __MINGW32__
|
8
|
+
// make pedantic compiler happy
|
9
|
+
typedef struct {
|
10
|
+
int bogus;
|
11
|
+
} bogus_s;
|
12
|
+
|
13
|
+
#else
|
7
14
|
#include <fio.h>
|
8
15
|
|
9
16
|
/**
|
@@ -639,3 +646,4 @@ void FIO_TLS_WEAK fio_tls_destroy(fio_tls_s *tls) {
|
|
639
646
|
}
|
640
647
|
|
641
648
|
#endif /* Library compiler flags */
|
649
|
+
#endif
|
@@ -4,6 +4,13 @@ License: MIT
|
|
4
4
|
|
5
5
|
Feel free to copy, use and enjoy according to the license provided.
|
6
6
|
*/
|
7
|
+
#ifdef __MINGW32__
|
8
|
+
// make pedantic compiler happy
|
9
|
+
typedef struct {
|
10
|
+
int bogus;
|
11
|
+
} bogus_s;
|
12
|
+
|
13
|
+
#else
|
7
14
|
#include <fio.h>
|
8
15
|
|
9
16
|
/**
|
@@ -1046,3 +1053,4 @@ void FIO_TLS_WEAK fio_tls_destroy(fio_tls_s *tls) {
|
|
1046
1053
|
}
|
1047
1054
|
|
1048
1055
|
#endif /* Library compiler flags */
|
1056
|
+
#endif
|
data/ext/iodine/fio_tmpfile.h
CHANGED
@@ -18,10 +18,22 @@ License: MIT
|
|
18
18
|
#include <sys/types.h>
|
19
19
|
#include <unistd.h>
|
20
20
|
|
21
|
+
#ifdef __MINGW32__
|
22
|
+
#include <fileapi.h>
|
23
|
+
#endif
|
24
|
+
|
21
25
|
static inline int fio_tmpfile(void) {
|
22
26
|
// create a temporary file to contain the data.
|
23
27
|
int fd = 0;
|
24
|
-
#ifdef
|
28
|
+
#ifdef __MINGW32__
|
29
|
+
char name_template[] = "fio";
|
30
|
+
TCHAR temp_path[(MAX_PATH-14)];
|
31
|
+
TCHAR temp_filename[MAX_PATH];
|
32
|
+
GetTempPath(MAX_PATH - 14, temp_path);
|
33
|
+
GetTempFileNameA(temp_path, name_template, 0, temp_filename);
|
34
|
+
fd = _open(temp_filename, _O_CREAT | _O_RDWR);
|
35
|
+
_chmod(temp_filename, _S_IREAD | _S_IWRITE);
|
36
|
+
#elif defined(P_tmpdir)
|
25
37
|
if (P_tmpdir[sizeof(P_tmpdir) - 1] == '/') {
|
26
38
|
char name_template[] = P_tmpdir "facil_io_tmpfile_XXXXXXXX";
|
27
39
|
fd = mkstemp(name_template);
|
data/ext/iodine/fiobj_data.c
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#if defined(__unix__) || defined(__APPLE__) || defined(__linux__) || \
|
2
|
-
defined(__CYGWIN__) /* require POSIX */
|
2
|
+
defined(__CYGWIN__) || defined(__MINGW32__) /* require POSIX */
|
3
3
|
/*
|
4
4
|
Copyright: Boaz Segev, 2017-2019
|
5
5
|
License: MIT
|
@@ -78,6 +78,7 @@ static void fiobj_data_copy_parent(FIOBJ o) {
|
|
78
78
|
switch (obj2io(obj2io(o)->source.parent)->fd) {
|
79
79
|
case -1:
|
80
80
|
obj2io(o)->buffer = fio_malloc(obj2io(o)->len + 1);
|
81
|
+
FIO_ASSERT_ALLOC(obj2io(o)->buffer);
|
81
82
|
memcpy(obj2io(o)->buffer,
|
82
83
|
obj2io(obj2io(o)->source.parent)->buffer + obj2io(o)->capa,
|
83
84
|
obj2io(o)->len);
|
@@ -102,7 +103,11 @@ static void fiobj_data_copy_parent(FIOBJ o) {
|
|
102
103
|
if (data.len + pos > obj2io(o)->len)
|
103
104
|
data.len = obj2io(o)->len - pos;
|
104
105
|
retry_int:
|
106
|
+
#ifdef __MINGW32__
|
107
|
+
written = pwrite(obj2io(o)->fd, data.data, data.len, 0);
|
108
|
+
#else
|
105
109
|
written = write(obj2io(o)->fd, data.data, data.len);
|
110
|
+
#endif
|
106
111
|
if (written < 0) {
|
107
112
|
if (errno == EINTR)
|
108
113
|
goto retry_int;
|
@@ -958,7 +963,6 @@ intptr_t fiobj_data_write(FIOBJ io, void *buffer, uintptr_t length) {
|
|
958
963
|
/* Unslice slices */
|
959
964
|
if (obj2io(io)->fd == -2)
|
960
965
|
fiobj_data_assert_dynamic(io);
|
961
|
-
|
962
966
|
if (obj2io(io)->fd == -1) {
|
963
967
|
/* String Code */
|
964
968
|
fiobj_data_pre_write(io, length + 1);
|
@@ -967,7 +971,6 @@ intptr_t fiobj_data_write(FIOBJ io, void *buffer, uintptr_t length) {
|
|
967
971
|
obj2io(io)->buffer[obj2io(io)->len] = 0;
|
968
972
|
return length;
|
969
973
|
}
|
970
|
-
|
971
974
|
/* File Code */
|
972
975
|
return pwrite(obj2io(io)->fd, buffer, length, fiobj_data_get_fd_size(io));
|
973
976
|
}
|
@@ -1046,7 +1049,6 @@ void fiobj_data_test(void) {
|
|
1046
1049
|
fprintf(stderr, "* `fiobj_data_read` operation overflow - FAILED!\n");
|
1047
1050
|
exit(-1);
|
1048
1051
|
}
|
1049
|
-
|
1050
1052
|
if (fiobj_obj2cstr(strio).len != fiobj_obj2cstr(text).len ||
|
1051
1053
|
fiobj_obj2cstr(fdio).len != fiobj_obj2cstr(text).len) {
|
1052
1054
|
fprintf(stderr, "* `write` operation FAILED!\n");
|
data/ext/iodine/fiobj_data.h
CHANGED
@@ -3,7 +3,8 @@ Copyright: Boaz Segev, 2017-2019
|
|
3
3
|
License: MIT
|
4
4
|
*/
|
5
5
|
#if !defined(H_FIOBJ_IO_H) && (defined(__unix__) || defined(__APPLE__) || \
|
6
|
-
defined(__linux__) || defined(__CYGWIN__)
|
6
|
+
defined(__linux__) || defined(__CYGWIN__) || \
|
7
|
+
defined(__MINGW32__))
|
7
8
|
|
8
9
|
/**
|
9
10
|
* A dynamic type for reading / writing to a local file, a temporary file or an
|
data/ext/iodine/fiobj_hash.c
CHANGED
@@ -36,6 +36,8 @@ License: MIT
|
|
36
36
|
|
37
37
|
#include <errno.h>
|
38
38
|
|
39
|
+
#include <pthread.h>
|
40
|
+
|
39
41
|
/* *****************************************************************************
|
40
42
|
Hash types
|
41
43
|
***************************************************************************** */
|
@@ -69,18 +71,34 @@ static void fiobj_hash_dealloc(FIOBJ o, void (*task)(FIOBJ, void *),
|
|
69
71
|
fio_free(FIOBJ2PTR(o));
|
70
72
|
}
|
71
73
|
|
72
|
-
static
|
74
|
+
static pthread_key_t each_at_key;
|
75
|
+
static pthread_once_t each_at_key_once = PTHREAD_ONCE_INIT;
|
76
|
+
static void init_each_at_key(void) {
|
77
|
+
pthread_key_create(&each_at_key, free);
|
78
|
+
}
|
79
|
+
static void init_each_at_key_ptr(void) {
|
80
|
+
FIOBJ *eak = malloc(sizeof(FIOBJ));
|
81
|
+
FIO_ASSERT_ALLOC(eak);
|
82
|
+
*eak = FIOBJ_INVALID;
|
83
|
+
pthread_setspecific(each_at_key, eak);
|
84
|
+
}
|
73
85
|
|
74
86
|
static size_t fiobj_hash_each1(FIOBJ o, size_t start_at,
|
75
87
|
int (*task)(FIOBJ obj, void *arg), void *arg) {
|
76
88
|
assert(o && FIOBJ_TYPE_IS(o, FIOBJ_T_HASH));
|
77
|
-
|
89
|
+
pthread_once(&each_at_key_once, init_each_at_key);
|
90
|
+
FIOBJ *each_at_key_ptr = (FIOBJ *)pthread_getspecific(each_at_key);
|
91
|
+
if (!each_at_key_ptr) {
|
92
|
+
init_each_at_key_ptr();
|
93
|
+
each_at_key_ptr = (FIOBJ *)pthread_getspecific(each_at_key);
|
94
|
+
}
|
95
|
+
FIOBJ old_each_at_key = *each_at_key_ptr;
|
78
96
|
fio_hash___s *hash = &obj2hash(o)->hash;
|
79
97
|
size_t count = 0;
|
80
98
|
if (hash->count == hash->pos) {
|
81
99
|
/* no holes in the hash, we can work as we please. */
|
82
100
|
for (count = start_at; count < hash->count; ++count) {
|
83
|
-
|
101
|
+
*each_at_key_ptr = hash->ordered[count].obj.key;
|
84
102
|
if (task((FIOBJ)hash->ordered[count].obj.obj, arg) == -1) {
|
85
103
|
++count;
|
86
104
|
goto end;
|
@@ -100,17 +118,25 @@ static size_t fiobj_hash_each1(FIOBJ o, size_t start_at,
|
|
100
118
|
if (hash->ordered[pos].obj.key == FIOBJ_INVALID)
|
101
119
|
continue;
|
102
120
|
++count;
|
103
|
-
|
121
|
+
*each_at_key_ptr = hash->ordered[pos].obj.key;
|
104
122
|
if (task((FIOBJ)hash->ordered[pos].obj.obj, arg) == -1)
|
105
123
|
break;
|
106
124
|
}
|
107
125
|
}
|
108
126
|
end:
|
109
|
-
|
127
|
+
*each_at_key_ptr = old_each_at_key;
|
110
128
|
return count;
|
111
129
|
}
|
112
130
|
|
113
|
-
FIOBJ fiobj_hash_key_in_loop(void) {
|
131
|
+
FIOBJ fiobj_hash_key_in_loop(void) {
|
132
|
+
pthread_once(&each_at_key_once, init_each_at_key);
|
133
|
+
FIOBJ *each_at_key_ptr = (FIOBJ *)pthread_getspecific(each_at_key);
|
134
|
+
if (!each_at_key_ptr) {
|
135
|
+
init_each_at_key_ptr();
|
136
|
+
each_at_key_ptr = (FIOBJ *)pthread_getspecific(each_at_key);
|
137
|
+
}
|
138
|
+
return *each_at_key_ptr;
|
139
|
+
}
|
114
140
|
|
115
141
|
static size_t fiobj_hash_is_eq(const FIOBJ self, const FIOBJ other) {
|
116
142
|
if (fio_hash___count(&obj2hash(self)->hash) !=
|
data/ext/iodine/fiobj_mustache.c
CHANGED
@@ -240,12 +240,20 @@ Testing
|
|
240
240
|
#if DEBUG
|
241
241
|
static inline void mustache_save2file(char const *filename, char const *data,
|
242
242
|
size_t length) {
|
243
|
+
#ifdef __MINGW32__
|
244
|
+
int fd = _open(filename, _O_CREAT | _O_RDWR);
|
245
|
+
#else
|
243
246
|
int fd = open(filename, O_CREAT | O_RDWR, 0);
|
247
|
+
#endif
|
244
248
|
if (fd == -1) {
|
245
249
|
perror("Couldn't open / create file for template testing");
|
246
250
|
exit(-1);
|
247
251
|
}
|
252
|
+
#ifdef __MINGW32__
|
253
|
+
_chmod(filename, _S_IREAD | _S_IWRITE);
|
254
|
+
#else
|
248
255
|
fchmod(fd, 0777);
|
256
|
+
#endif
|
249
257
|
if (pwrite(fd, data, length, 0) != (ssize_t)length) {
|
250
258
|
perror("Mustache template write error");
|
251
259
|
exit(-1);
|
@@ -265,6 +273,7 @@ void fiobj_mustache_test(void) {
|
|
265
273
|
"{{=<< >>=}}* Users:\r\n<<#users>><<id>>. <<& name>> "
|
266
274
|
"(<<name>>)\r\n<</users>>\r\nNested: <<& nested.item >>.";
|
267
275
|
char const *template_name = "mustache_test_template.mustache";
|
276
|
+
fprintf(stderr, "mustache test saving template %s\n", template_name);
|
268
277
|
mustache_save2file(template_name, template, strlen(template));
|
269
278
|
mustache_s *m =
|
270
279
|
fiobj_mustache_load((fio_str_info_s){.data = (char *)template_name});
|
data/ext/iodine/fiobj_numbers.c
CHANGED
@@ -12,6 +12,8 @@ License: MIT
|
|
12
12
|
#include <errno.h>
|
13
13
|
#include <math.h>
|
14
14
|
|
15
|
+
#include <pthread.h>
|
16
|
+
|
15
17
|
/* *****************************************************************************
|
16
18
|
Numbers Type
|
17
19
|
***************************************************************************** */
|
@@ -33,7 +35,17 @@ typedef struct {
|
|
33
35
|
Numbers VTable
|
34
36
|
***************************************************************************** */
|
35
37
|
|
36
|
-
static
|
38
|
+
static pthread_key_t num_vt_buffer_key;
|
39
|
+
static pthread_once_t num_vt_buffer_once = PTHREAD_ONCE_INIT;
|
40
|
+
static void init_num_vt_buffer_key(void) {
|
41
|
+
pthread_key_create(&num_vt_buffer_key, free);
|
42
|
+
}
|
43
|
+
static void init_num_vt_buffer_ptr(void) {
|
44
|
+
char *num_vt_buffer = malloc(sizeof(char)*512);
|
45
|
+
FIO_ASSERT_ALLOC(num_vt_buffer);
|
46
|
+
memset(num_vt_buffer, 0, sizeof(char)*512);
|
47
|
+
pthread_setspecific(num_vt_buffer_key, num_vt_buffer);
|
48
|
+
}
|
37
49
|
|
38
50
|
static intptr_t fio_i2i(const FIOBJ o) { return obj2num(o)->i; }
|
39
51
|
static intptr_t fio_f2i(const FIOBJ o) {
|
@@ -46,6 +58,12 @@ static size_t fio_itrue(const FIOBJ o) { return (obj2num(o)->i != 0); }
|
|
46
58
|
static size_t fio_ftrue(const FIOBJ o) { return (obj2float(o)->f != 0); }
|
47
59
|
|
48
60
|
static fio_str_info_s fio_i2str(const FIOBJ o) {
|
61
|
+
pthread_once(&num_vt_buffer_once, init_num_vt_buffer_key);
|
62
|
+
char *num_buffer = pthread_getspecific(num_vt_buffer_key);
|
63
|
+
if (!num_buffer) {
|
64
|
+
init_num_vt_buffer_ptr();
|
65
|
+
num_buffer = pthread_getspecific(num_vt_buffer_key);
|
66
|
+
}
|
49
67
|
return (fio_str_info_s){
|
50
68
|
.data = num_buffer,
|
51
69
|
.len = fio_ltoa(num_buffer, obj2num(o)->i, 10),
|
@@ -60,6 +78,12 @@ static fio_str_info_s fio_f2str(const FIOBJ o) {
|
|
60
78
|
else
|
61
79
|
return (fio_str_info_s){.data = (char *)"-Infinity", .len = 9};
|
62
80
|
}
|
81
|
+
pthread_once(&num_vt_buffer_once, init_num_vt_buffer_key);
|
82
|
+
char *num_buffer = pthread_getspecific(num_vt_buffer_key);
|
83
|
+
if (!num_buffer) {
|
84
|
+
init_num_vt_buffer_ptr();
|
85
|
+
num_buffer = pthread_getspecific(num_vt_buffer_key);
|
86
|
+
}
|
63
87
|
return (fio_str_info_s){
|
64
88
|
.data = num_buffer,
|
65
89
|
.len = fio_ftoa(num_buffer, obj2float(o)->f, 10),
|
@@ -126,14 +150,30 @@ FIOBJ fiobj_num_new_bignum(intptr_t num) {
|
|
126
150
|
// FIOBJ_IS_ALLOCATED(target)); obj2num(target)->i = num;
|
127
151
|
// }
|
128
152
|
|
153
|
+
static pthread_key_t num_ret_key;
|
154
|
+
static pthread_once_t num_ret_once = PTHREAD_ONCE_INIT;
|
155
|
+
static void init_num_ret_key(void) {
|
156
|
+
pthread_key_create(&num_ret_key, free);
|
157
|
+
}
|
158
|
+
static void init_num_ret_ptr(void) {
|
159
|
+
fiobj_num_s *ret = malloc(sizeof(fiobj_num_s));
|
160
|
+
FIO_ASSERT_ALLOC(ret);
|
161
|
+
memset(ret, 0, sizeof(fiobj_num_s));
|
162
|
+
pthread_setspecific(num_ret_key, ret);
|
163
|
+
}
|
129
164
|
/** Creates a temporary Number object. This ignores `fiobj_free`. */
|
130
165
|
FIOBJ fiobj_num_tmp(intptr_t num) {
|
131
|
-
|
132
|
-
ret = (
|
166
|
+
pthread_once(&num_ret_once, init_num_ret_key);
|
167
|
+
fiobj_num_s *ret = pthread_getspecific(num_ret_key);
|
168
|
+
if (!ret) {
|
169
|
+
init_num_ret_ptr();
|
170
|
+
ret = pthread_getspecific(num_ret_key);
|
171
|
+
}
|
172
|
+
*ret = (fiobj_num_s){
|
133
173
|
.head = {.type = FIOBJ_T_NUMBER, .ref = ((~(uint32_t)0) >> 4)},
|
134
174
|
.i = num,
|
135
175
|
};
|
136
|
-
return (FIOBJ)
|
176
|
+
return (FIOBJ)ret;
|
137
177
|
}
|
138
178
|
|
139
179
|
/* *****************************************************************************
|
@@ -164,10 +204,26 @@ void fiobj_float_set(FIOBJ obj, double num) {
|
|
164
204
|
obj2float(obj)->f = num;
|
165
205
|
}
|
166
206
|
|
207
|
+
static pthread_key_t float_ret_key;
|
208
|
+
static pthread_once_t float_ret_once = PTHREAD_ONCE_INIT;
|
209
|
+
static void init_float_ret_key(void) {
|
210
|
+
pthread_key_create(&float_ret_key, free);
|
211
|
+
}
|
212
|
+
static void init_float_ret_ptr(void) {
|
213
|
+
fiobj_float_s *ret = malloc(sizeof(fiobj_float_s));
|
214
|
+
FIO_ASSERT_ALLOC(ret);
|
215
|
+
memset(ret, 0, sizeof(fiobj_float_s));
|
216
|
+
pthread_setspecific(float_ret_key, ret);
|
217
|
+
}
|
167
218
|
/** Creates a temporary Number object. This ignores `fiobj_free`. */
|
168
219
|
FIOBJ fiobj_float_tmp(double num) {
|
169
|
-
|
170
|
-
ret = (
|
220
|
+
pthread_once(&float_ret_once, init_float_ret_key);
|
221
|
+
fiobj_float_s *ret = pthread_getspecific(float_ret_key);
|
222
|
+
if (!ret) {
|
223
|
+
init_float_ret_ptr();
|
224
|
+
ret = pthread_getspecific(float_ret_key);
|
225
|
+
}
|
226
|
+
*ret = (fiobj_float_s){
|
171
227
|
.head =
|
172
228
|
{
|
173
229
|
.type = FIOBJ_T_FLOAT,
|
@@ -175,20 +231,42 @@ FIOBJ fiobj_float_tmp(double num) {
|
|
175
231
|
},
|
176
232
|
.f = num,
|
177
233
|
};
|
178
|
-
return (FIOBJ)
|
234
|
+
return (FIOBJ)ret;
|
179
235
|
}
|
180
236
|
|
181
237
|
/* *****************************************************************************
|
182
238
|
Numbers to Strings - Buffered
|
183
239
|
***************************************************************************** */
|
184
240
|
|
185
|
-
static
|
241
|
+
static pthread_key_t num_str_buffer_key;
|
242
|
+
static pthread_once_t num_str_buffer_once = PTHREAD_ONCE_INIT;
|
243
|
+
static void init_num_str_buffer_key(void) {
|
244
|
+
pthread_key_create(&num_str_buffer_key, free);
|
245
|
+
}
|
246
|
+
static void init_num_str_buffer_ptr(void) {
|
247
|
+
char *num_str_buffer = malloc(sizeof(char)*512);
|
248
|
+
FIO_ASSERT_ALLOC(num_str_buffer);
|
249
|
+
memset(num_str_buffer, 0, sizeof(char)*512);
|
250
|
+
pthread_setspecific(num_str_buffer_key, num_str_buffer);
|
251
|
+
}
|
186
252
|
|
187
253
|
fio_str_info_s fio_ltocstr(long i) {
|
254
|
+
pthread_once(&num_str_buffer_once, init_num_str_buffer_key);
|
255
|
+
char *num_buffer = pthread_getspecific(num_str_buffer_key);
|
256
|
+
if (!num_buffer) {
|
257
|
+
init_num_str_buffer_ptr();
|
258
|
+
num_buffer = pthread_getspecific(num_str_buffer_key);
|
259
|
+
}
|
188
260
|
return (fio_str_info_s){.data = num_buffer,
|
189
261
|
.len = fio_ltoa(num_buffer, i, 10)};
|
190
262
|
}
|
191
263
|
fio_str_info_s fio_ftocstr(double f) {
|
264
|
+
pthread_once(&num_str_buffer_once, init_num_str_buffer_key);
|
265
|
+
char *num_buffer = pthread_getspecific(num_str_buffer_key);
|
266
|
+
if (!num_buffer) {
|
267
|
+
init_num_str_buffer_ptr();
|
268
|
+
num_buffer = pthread_getspecific(num_str_buffer_key);
|
269
|
+
}
|
192
270
|
return (fio_str_info_s){.data = num_buffer,
|
193
271
|
.len = fio_ftoa(num_buffer, f, 10)};
|
194
272
|
}
|
data/ext/iodine/fiobj_str.c
CHANGED
@@ -37,6 +37,8 @@ License: MIT
|
|
37
37
|
#define PATH_MAX PAGE_SIZE
|
38
38
|
#endif
|
39
39
|
|
40
|
+
#include <pthread.h>
|
41
|
+
|
40
42
|
/* *****************************************************************************
|
41
43
|
String Type
|
42
44
|
***************************************************************************** */
|
@@ -176,22 +178,33 @@ FIOBJ fiobj_str_move(char *str, size_t len, size_t capacity) {
|
|
176
178
|
return ((uintptr_t)s | FIOBJECT_STRING_FLAG);
|
177
179
|
}
|
178
180
|
|
181
|
+
static pthread_key_t str_tmp_key;
|
182
|
+
static pthread_once_t str_tmp_once = PTHREAD_ONCE_INIT;
|
183
|
+
static void init_str_tmp_key(void) {
|
184
|
+
pthread_key_create(&str_tmp_key, free);
|
185
|
+
}
|
186
|
+
static void init_str_tmp_key_ptr(void) {
|
187
|
+
fiobj_str_s *tmp = malloc(sizeof(fiobj_str_s));
|
188
|
+
FIO_ASSERT_ALLOC(tmp);
|
189
|
+
tmp->head.ref = ((~(uint32_t)0) >> 4);
|
190
|
+
tmp->head.type = FIOBJ_T_STRING;
|
191
|
+
tmp->str.small = 1;
|
192
|
+
pthread_setspecific(str_tmp_key, tmp);
|
193
|
+
}
|
179
194
|
/**
|
180
195
|
* Returns a thread-static temporary string. Avoid calling `fiobj_dup` or
|
181
196
|
* `fiobj_free`.
|
182
197
|
*/
|
183
198
|
FIOBJ fiobj_str_tmp(void) {
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
tmp
|
193
|
-
fio_str_resize(&tmp.str, 0);
|
194
|
-
return ((uintptr_t)&tmp | FIOBJECT_STRING_FLAG);
|
199
|
+
pthread_once(&str_tmp_once, init_str_tmp_key);
|
200
|
+
fiobj_str_s *tmp = (fiobj_str_s *)pthread_getspecific(str_tmp_key);
|
201
|
+
if (!tmp) {
|
202
|
+
init_str_tmp_key_ptr();
|
203
|
+
tmp = (fiobj_str_s *)pthread_getspecific(str_tmp_key);
|
204
|
+
}
|
205
|
+
tmp->str.frozen = 0;
|
206
|
+
fio_str_resize(&tmp->str, 0);
|
207
|
+
return ((uintptr_t)tmp | FIOBJECT_STRING_FLAG);
|
195
208
|
}
|
196
209
|
|
197
210
|
/** Prevents the String object from being changed. */
|
data/ext/iodine/fiobject.c
CHANGED
@@ -102,7 +102,7 @@ size_t __attribute__((weak)) fio_ltoa(char *dest, int64_t num, uint8_t base) {
|
|
102
102
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
103
103
|
|
104
104
|
size_t len = 0;
|
105
|
-
char buf[48]; /* we only need up to 20 for base 10, but base 3 needs 41... */
|
105
|
+
char buf[48] = {0}; /* we only need up to 20 for base 10, but base 3 needs 41... */
|
106
106
|
|
107
107
|
if (!num)
|
108
108
|
goto zero;
|
data/ext/iodine/fiobject.h
CHANGED
@@ -502,7 +502,7 @@ fio_str_info_s fio_ftocstr(double);
|
|
502
502
|
/**
|
503
503
|
* Returns a C String (NUL terminated) using the `fio_str_info_s` data type.
|
504
504
|
*
|
505
|
-
* The
|
505
|
+
* The String is binary safe and might contain NUL bytes in the middle as well as
|
506
506
|
* a terminating NUL.
|
507
507
|
*
|
508
508
|
* If a a Number or a Float are passed to the function, they
|
@@ -554,11 +554,13 @@ FIO_INLINE uint64_t fiobj_obj2hash(const FIOBJ o) {
|
|
554
554
|
if (!FIOBJ_IS_ALLOCATED(o))
|
555
555
|
return (uint64_t)o;
|
556
556
|
fio_str_info_s s = fiobj_obj2cstr(o);
|
557
|
-
return FIO_HASH_FN(s.data, s.len, &fiobj_each2,
|
557
|
+
return FIO_HASH_FN(s.data, s.len, (uintptr_t)&fiobj_each2,
|
558
|
+
(uintptr_t)&fiobj_free_complex_object);
|
558
559
|
}
|
559
560
|
|
560
561
|
FIO_INLINE uint64_t fiobj_hash_string(const void *data, size_t len) {
|
561
|
-
return FIO_HASH_FN(data, len, &fiobj_each2,
|
562
|
+
return FIO_HASH_FN(data, len, (uintptr_t)&fiobj_each2,
|
563
|
+
(uintptr_t)&fiobj_free_complex_object);
|
562
564
|
}
|
563
565
|
|
564
566
|
/**
|