iodine 0.7.41 → 0.7.45
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +1 -1
- data/.gitignore +1 -0
- data/CHANGELOG.md +24 -0
- data/README.md +2 -2
- data/SPEC-PubSub-Draft.md +89 -47
- data/SPEC-WebSocket-Draft.md +92 -55
- data/examples/async_task.ru +92 -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 +66 -10
- 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 +66 -1
- data/ext/iodine/iodine.h +3 -0
- data/ext/iodine/iodine_caller.c +48 -8
- data/ext/iodine/iodine_connection.c +24 -8
- data/ext/iodine/iodine_http.c +32 -8
- data/ext/iodine/iodine_mustache.c +2 -4
- data/ext/iodine/iodine_rack_io.c +21 -0
- 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
- data/lib/rack/handler/iodine.rb +6 -0
- 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
|
/**
|