iodine 0.7.15 → 0.7.16
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of iodine might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +8 -0
- data/README.md +13 -11
- data/examples/redis.ru +11 -6
- data/exe/iodine +6 -1
- data/ext/iodine/fio.c +90 -38
- data/ext/iodine/fio.h +124 -37
- data/ext/iodine/fio_cli.c +51 -59
- data/ext/iodine/fio_cli.h +58 -19
- data/ext/iodine/fio_siphash.c +1 -54
- data/ext/iodine/fio_siphash.h +1 -1
- data/ext/iodine/http1.c +7 -1
- data/ext/iodine/http1_parser.c +4 -3
- data/ext/iodine/http_internal.h +3 -0
- data/ext/iodine/iodine.c +32 -30
- data/ext/iodine/iodine_mustache.c +11 -8
- data/ext/iodine/iodine_pubsub.c +2 -5
- data/ext/iodine/websockets.c +5 -1
- data/lib/iodine/mustache.rb +2 -2
- data/lib/iodine/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4813b7d2deb5b0dede2e40d240e295f10cdcef94effb743eeb0293317e84fc3e
|
4
|
+
data.tar.gz: 4fb3632e530571ad598c50f42e3eca989aca0425c00df041d590ca26fdcc2b8e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d632268e49abf09a61e7eaa0d8905f9c4bef2f303784d4d3eca0fd9a6bc29952b28eb7c9709ab34d95324b0bdbdc866a98c0520d9df5cc560b3afba83f5e940f
|
7
|
+
data.tar.gz: 28c9fa08377cad5fba31cda50186598839abe336f85c882efea480c4bed467e1e10e0df5c18fe72ef48e97ed2b92c4bdf68264373169cfeeb82a82788ee6b966
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,14 @@ Please notice that this change log contains changes for upcoming releases as wel
|
|
6
6
|
|
7
7
|
## Changes:
|
8
8
|
|
9
|
+
#### Change log v.0.7.16
|
10
|
+
|
11
|
+
**Security**: (`fio`) security fixes from the facil.io core library (updated to 0.7.0.beta6).
|
12
|
+
|
13
|
+
**Update**: (`iodine`) better Redis support from CLI and environment (by setting the `IODINE_REDIS_URL` environment variable).
|
14
|
+
|
15
|
+
**Optimization**: (`Iodine::Mustache`) optimized worst case scenario seeking by seeking Symbols before Strings, which improved seeking times.
|
16
|
+
|
9
17
|
#### Change log v.0.7.15
|
10
18
|
|
11
19
|
**Fix**: (`fio`) fixed a minor memory leak in cluster mode, caused by the root process not freeing the hash map used for child process subscription monitoring (only effected hot restarts).
|
data/README.md
CHANGED
@@ -7,9 +7,13 @@
|
|
7
7
|
|
8
8
|
[![Logo](https://github.com/boazsegev/iodine/raw/master/logo.png)](https://github.com/boazsegev/iodine)
|
9
9
|
|
10
|
-
|
10
|
+
I believe that network concerns should be separated from application concerns - application developers really shouldn't need to worry about the transport layer.
|
11
11
|
|
12
|
-
|
12
|
+
And I know that these network concerns are more than just about the web server. Which is why iodine is more than just an HTTP server.
|
13
|
+
|
14
|
+
Iodine is a fast concurrent web server for real-time Ruby applications, but it's also so much more. Iodine includes native support for:
|
15
|
+
|
16
|
+
* WebSockets and EventSource (SSE);
|
13
17
|
* Pub/Sub (with optional Redis Pub/Sub scaling);
|
14
18
|
* Static file service (with automatic `gzip` support for pre-compressed versions);
|
15
19
|
* HTTP/1.1 keep-alive and pipelining;
|
@@ -25,9 +29,9 @@ Iodine is an **evented** framework with a simple API that ports much of the [C f
|
|
25
29
|
|
26
30
|
* Iodine can handle **thousands of concurrent connections** (tested with more then 20K connections on Linux)!
|
27
31
|
|
28
|
-
* Iodine is ideal for **Linux/Unix** based systems (i.e. macOS, Ubuntu, FreeBSD etc'), which are ideal for evented IO (while Windows and Solaris are better at IO *completion* events, which are
|
32
|
+
* Iodine is ideal for **Linux/Unix** based systems (i.e. macOS, Ubuntu, FreeBSD etc'), which are ideal for evented IO (while Windows and Solaris are better at IO *completion* events, which are very different).
|
29
33
|
|
30
|
-
Iodine is a C extension for Ruby, developed and optimized for Ruby MRI 2.2.2 and up... it should support the whole Ruby 2.0 MRI family, but
|
34
|
+
Iodine is a C extension for Ruby, developed and optimized for Ruby MRI 2.2.2 and up... it should support the whole Ruby 2.0 MRI family, but CI tests start at Ruby 2.2.2.
|
31
35
|
|
32
36
|
## Iodine - a fast & powerful HTTP + Websockets server with native Pub/Sub
|
33
37
|
|
@@ -63,13 +67,11 @@ bundler exec iodine -p $PORT -t 16 -w 1
|
|
63
67
|
|
64
68
|
### Heap Fragmentation Protection
|
65
69
|
|
66
|
-
Iodine includes a network oriented custom memory allocator,
|
67
|
-
|
68
|
-
This allows the heap to be divided, naturally, into long-living objects (allocated normally) and short living objects (allocated using the iodine allocator).
|
70
|
+
Iodine includes a fast, network oriented, custom memory allocator, optimizing away some of the work usually placed on the Ruby Garbage Collector (GC).
|
69
71
|
|
70
|
-
This approach helps to minimize heap fragmentation for long running processes.
|
72
|
+
This approach helps to minimize heap fragmentation for long running processes, by grouping many short-lived objects into a common memory space.
|
71
73
|
|
72
|
-
It's still recommended to consider [jemalloc](http://jemalloc.net) or other allocators
|
74
|
+
It's still recommended to consider [jemalloc](http://jemalloc.net) or other allocators that also help mitigate heap fragmentation issues.
|
73
75
|
|
74
76
|
### Static file serving support
|
75
77
|
|
@@ -301,9 +303,9 @@ bundler exec iodine -p $PORT -v 2>&1
|
|
301
303
|
|
302
304
|
### Built-in support for Sequel and ActiveRecord
|
303
305
|
|
304
|
-
It's a well known fact that Database connections require special attention when using `fork`-ing servers (multi-process servers) such as Puma, Passenger and iodine.
|
306
|
+
It's a well known fact that [Database connections require special attention when using `fork`-ing servers (multi-process servers)](https://devcenter.heroku.com/articles/concurrency-and-database-connections#multi-process-servers) such as Puma, Passenger (Pro) and iodine.
|
305
307
|
|
306
|
-
However, it's also true that these issues go unnoticed by many developers, since application developers are (rightfully) focused on the application rather than the infrastructure.
|
308
|
+
However, it's also true that [these issues go unnoticed by many developers](https://stackoverflow.com/a/45570999/4025095), since application developers are (rightfully) focused on the application rather than the infrastructure.
|
307
309
|
|
308
310
|
With iodine, there's no need to worry.
|
309
311
|
|
data/examples/redis.ru
CHANGED
@@ -1,14 +1,19 @@
|
|
1
1
|
# This example implements a Redis pub/sub engine according to the Iodine::PubSub::Engine specifications.
|
2
2
|
#
|
3
|
-
# Run this applications on two ports, in two terminals to see the synchronization is action
|
3
|
+
# Run this applications on two ports, in two terminals to see the synchronization is action:
|
4
4
|
#
|
5
|
-
#
|
6
|
-
#
|
5
|
+
# IODINE_REDIS_URL=redis://localhost:6379/0 iodine -t 1 -p 3000 redis.ru
|
6
|
+
# IODINE_REDIS_URL=redis://localhost:6379/0 iodine -t 1 -p 3030 redis.ru
|
7
|
+
#
|
8
|
+
# Or:
|
9
|
+
#
|
10
|
+
# iodine -t 1 -p 3000 redis.ru -redis redis://localhost:6379/0
|
11
|
+
# iodine -t 1 -p 3030 redis.ru -redis redis://localhost:6379/0
|
7
12
|
#
|
8
13
|
require 'iodine'
|
9
14
|
# initialize the Redis engine for each Iodine process.
|
10
|
-
if
|
11
|
-
|
15
|
+
if Iodine::DEFAULT_HTTP_ARGS[:redis_]
|
16
|
+
puts "* Redis support automatically detected."
|
12
17
|
else
|
13
18
|
puts "* No Redis, it's okay, pub/sub will support the process cluster."
|
14
19
|
end
|
@@ -47,7 +52,7 @@ class WS_RedisPubSub
|
|
47
52
|
client.publish "chat", "#{@name} entered the chat."
|
48
53
|
end
|
49
54
|
# send a message, letting the client know the server is suggunt down.
|
50
|
-
def on_shutdown client
|
55
|
+
def on_shutdown client
|
51
56
|
client.write "Server shutting down. Goodbye."
|
52
57
|
end
|
53
58
|
# perform the echo
|
data/exe/iodine
CHANGED
data/ext/iodine/fio.c
CHANGED
@@ -5,9 +5,13 @@ License: MIT
|
|
5
5
|
Feel free to copy, use and enjoy according to the license provided.
|
6
6
|
***************************************************************************** */
|
7
7
|
|
8
|
+
#include <fio.h>
|
9
|
+
|
8
10
|
#define FIO_INCLUDE_STR
|
9
|
-
#
|
11
|
+
#include <fio.h>
|
10
12
|
|
13
|
+
#define FIO_FORCE_MALLOC_TMP 1
|
14
|
+
#define FIO_INCLUDE_LINKED_LIST
|
11
15
|
#include <fio.h>
|
12
16
|
|
13
17
|
#include <ctype.h>
|
@@ -2109,9 +2113,11 @@ static void deferred_on_ready(void *arg, void *arg2) {
|
|
2109
2113
|
}
|
2110
2114
|
|
2111
2115
|
static void deferred_on_data(void *uuid, void *arg2) {
|
2112
|
-
if (
|
2116
|
+
if (fio_is_closed((intptr_t)uuid)) {
|
2113
2117
|
return;
|
2114
2118
|
}
|
2119
|
+
if (!uuid_data(uuid).protocol)
|
2120
|
+
goto no_protocol;
|
2115
2121
|
fio_protocol_s *pr = protocol_try_lock(fio_uuid2fd(uuid), FIO_PR_LOCK_TASK);
|
2116
2122
|
if (!pr) {
|
2117
2123
|
if (errno == EBADF) {
|
@@ -2126,6 +2132,7 @@ static void deferred_on_data(void *uuid, void *arg2) {
|
|
2126
2132
|
fio_poll_add_read(fio_uuid2fd((intptr_t)uuid));
|
2127
2133
|
}
|
2128
2134
|
return;
|
2135
|
+
|
2129
2136
|
postpone:
|
2130
2137
|
if (arg2) {
|
2131
2138
|
/* the event is being forced, so force rescheduling */
|
@@ -2135,6 +2142,11 @@ postpone:
|
|
2135
2142
|
fio_poll_add_read(fio_uuid2fd((intptr_t)uuid));
|
2136
2143
|
}
|
2137
2144
|
return;
|
2145
|
+
|
2146
|
+
no_protocol:
|
2147
|
+
/* a missing protocol might still want to invoke the RW hook flush */
|
2148
|
+
deferred_on_ready(uuid, arg2);
|
2149
|
+
return;
|
2138
2150
|
}
|
2139
2151
|
|
2140
2152
|
static void deferred_ping(void *arg, void *arg2) {
|
@@ -2537,8 +2549,9 @@ static int fio_sock_write_buffer(int fd, fio_packet_s *packet) {
|
|
2537
2549
|
if (written > 0) {
|
2538
2550
|
packet->length -= written;
|
2539
2551
|
packet->offset += written;
|
2540
|
-
if (!packet->length)
|
2552
|
+
if (!packet->length) {
|
2541
2553
|
fio_sock_packet_rotate_unsafe(fd);
|
2554
|
+
}
|
2542
2555
|
}
|
2543
2556
|
return written;
|
2544
2557
|
}
|
@@ -2552,10 +2565,11 @@ static int fio_sock_write_from_fd(int fd, fio_packet_s *packet) {
|
|
2552
2565
|
packet->offset += sent;
|
2553
2566
|
packet->length -= sent;
|
2554
2567
|
retry:
|
2555
|
-
asked = (packet->
|
2556
|
-
|
2557
|
-
|
2558
|
-
|
2568
|
+
asked = pread(packet->data.fd, buff,
|
2569
|
+
((packet->length < BUFFER_FILE_READ_SIZE)
|
2570
|
+
? packet->length
|
2571
|
+
: BUFFER_FILE_READ_SIZE),
|
2572
|
+
packet->offset);
|
2559
2573
|
if (asked <= 0)
|
2560
2574
|
goto read_error;
|
2561
2575
|
sent = fd_data(fd).rw_hooks->write(fd2uuid(fd), fd_data(fd).rw_udata, buff,
|
@@ -2784,7 +2798,7 @@ void fio_close(intptr_t uuid) {
|
|
2784
2798
|
errno = EBADF;
|
2785
2799
|
return;
|
2786
2800
|
}
|
2787
|
-
if (uuid_data(uuid).packet) {
|
2801
|
+
if (uuid_data(uuid).packet || uuid_data(uuid).sock_lock) {
|
2788
2802
|
uuid_data(uuid).close = 1;
|
2789
2803
|
fio_poll_add_write(fio_uuid2fd(uuid));
|
2790
2804
|
return;
|
@@ -2914,7 +2928,7 @@ size_t fio_flush_all(void) {
|
|
2914
2928
|
if (!fio_data)
|
2915
2929
|
return 0;
|
2916
2930
|
size_t count = 0;
|
2917
|
-
for (uintptr_t i = 0; i
|
2931
|
+
for (uintptr_t i = 0; i <= fio_data->max_protocol_fd; ++i) {
|
2918
2932
|
if ((fd_data(i).open || fd_data(i).packet) && fio_flush(fd2uuid(i)) > 0)
|
2919
2933
|
++count;
|
2920
2934
|
}
|
@@ -2958,6 +2972,41 @@ const fio_rw_hook_s FIO_DEFAULT_RW_HOOKS = {
|
|
2958
2972
|
.cleanup = fio_hooks_default_cleanup,
|
2959
2973
|
};
|
2960
2974
|
|
2975
|
+
/**
|
2976
|
+
* Replaces an existing read/write hook with another from within a read/write
|
2977
|
+
* hook callback.
|
2978
|
+
*
|
2979
|
+
* Does NOT call any cleanup callbacks.
|
2980
|
+
*
|
2981
|
+
* Returns -1 on error, 0 on success.
|
2982
|
+
*/
|
2983
|
+
int fio_rw_hook_replace_unsafe(intptr_t uuid, fio_rw_hook_s *rw_hooks,
|
2984
|
+
void *udata) {
|
2985
|
+
int replaced = -1;
|
2986
|
+
uint8_t was_locked;
|
2987
|
+
intptr_t fd = fio_uuid2fd(uuid);
|
2988
|
+
if (!rw_hooks->read)
|
2989
|
+
rw_hooks->read = fio_hooks_default_read;
|
2990
|
+
if (!rw_hooks->write)
|
2991
|
+
rw_hooks->write = fio_hooks_default_write;
|
2992
|
+
if (!rw_hooks->flush)
|
2993
|
+
rw_hooks->flush = fio_hooks_default_flush;
|
2994
|
+
if (!rw_hooks->before_close)
|
2995
|
+
rw_hooks->before_close = fio_hooks_default_before_close;
|
2996
|
+
if (!rw_hooks->cleanup)
|
2997
|
+
rw_hooks->cleanup = fio_hooks_default_cleanup;
|
2998
|
+
/* protect against some fulishness... but not all of it. */
|
2999
|
+
was_locked = fio_trylock(&fd_data(fd).sock_lock);
|
3000
|
+
if (fd2uuid(fd) == uuid) {
|
3001
|
+
fd_data(fd).rw_hooks = rw_hooks;
|
3002
|
+
fd_data(fd).rw_udata = udata;
|
3003
|
+
replaced = 0;
|
3004
|
+
}
|
3005
|
+
if (!was_locked)
|
3006
|
+
fio_unlock(&fd_data(fd).sock_lock);
|
3007
|
+
return replaced;
|
3008
|
+
}
|
3009
|
+
|
2961
3010
|
/** Sets a socket hook state (a pointer to the struct). */
|
2962
3011
|
int fio_rw_hook_set(intptr_t uuid, fio_rw_hook_s *rw_hooks, void *udata) {
|
2963
3012
|
if (fio_is_closed(uuid))
|
@@ -3060,10 +3109,18 @@ static int fio_attach__internal(void *uuid_, void *protocol_) {
|
|
3060
3109
|
touchfd(fio_uuid2fd(uuid));
|
3061
3110
|
fio_unlock(&uuid_data(uuid).protocol_lock);
|
3062
3111
|
if (old_pr) {
|
3112
|
+
/* protocol replacement */
|
3063
3113
|
fio_defer_push_task(deferred_on_close, (void *)uuid, old_pr);
|
3114
|
+
if (!protocol) {
|
3115
|
+
/* hijacking */
|
3116
|
+
fio_poll_remove_fd(fio_uuid2fd(uuid));
|
3117
|
+
fio_poll_add_write(fio_uuid2fd(uuid));
|
3118
|
+
}
|
3064
3119
|
} else if (protocol) {
|
3120
|
+
/* adding a new uuid to the reactor */
|
3065
3121
|
fio_poll_add(fio_uuid2fd(uuid));
|
3066
3122
|
}
|
3123
|
+
fio_max_fd_min(fio_uuid2fd(uuid));
|
3067
3124
|
return 0;
|
3068
3125
|
|
3069
3126
|
invalid_uuid:
|
@@ -3313,23 +3370,6 @@ Initialize the library
|
|
3313
3370
|
|
3314
3371
|
static void fio_pubsub_on_fork(void);
|
3315
3372
|
|
3316
|
-
static void fio_mem_destroy(void);
|
3317
|
-
static void __attribute__((destructor)) fio_lib_destroy(void) {
|
3318
|
-
uint8_t add_eol = fio_is_master();
|
3319
|
-
fio_data->active = 0;
|
3320
|
-
fio_state_callback_force(FIO_CALL_AT_EXIT);
|
3321
|
-
fio_state_callback_clear_all();
|
3322
|
-
fio_defer_perform();
|
3323
|
-
fio_poll_close();
|
3324
|
-
fio_timer_clear_all();
|
3325
|
-
fio_free(fio_data);
|
3326
|
-
/* memory library destruction must be last */
|
3327
|
-
fio_mem_destroy();
|
3328
|
-
FIO_LOG_DEBUG("(%d) facil.io resources released, exit complete.", getpid());
|
3329
|
-
if (add_eol)
|
3330
|
-
fprintf(stderr, "\n"); /* add EOL to logs (logging adds EOL before text */
|
3331
|
-
}
|
3332
|
-
|
3333
3373
|
/* Called within a child process after it starts. */
|
3334
3374
|
static void fio_on_fork(void) {
|
3335
3375
|
fio_data->lock = FIO_LOCK_INIT;
|
@@ -3356,6 +3396,25 @@ static void fio_on_fork(void) {
|
|
3356
3396
|
fio_data->is_worker = 1;
|
3357
3397
|
}
|
3358
3398
|
|
3399
|
+
static void fio_mem_destroy(void);
|
3400
|
+
static void __attribute__((destructor)) fio_lib_destroy(void) {
|
3401
|
+
uint8_t add_eol = fio_is_master();
|
3402
|
+
fio_data->active = 0;
|
3403
|
+
fio_on_fork();
|
3404
|
+
fio_defer_perform();
|
3405
|
+
fio_state_callback_force(FIO_CALL_AT_EXIT);
|
3406
|
+
fio_state_callback_clear_all();
|
3407
|
+
fio_defer_perform();
|
3408
|
+
fio_poll_close();
|
3409
|
+
fio_timer_clear_all();
|
3410
|
+
fio_free(fio_data);
|
3411
|
+
/* memory library destruction must be last */
|
3412
|
+
fio_mem_destroy();
|
3413
|
+
FIO_LOG_DEBUG("(%d) facil.io resources released, exit complete.", getpid());
|
3414
|
+
if (add_eol)
|
3415
|
+
fprintf(stderr, "\n"); /* add EOL to logs (logging adds EOL before text */
|
3416
|
+
}
|
3417
|
+
|
3359
3418
|
static void fio_mem_init(void);
|
3360
3419
|
static void fio_cluster_init(void);
|
3361
3420
|
static void fio_pubsub_initialize(void);
|
@@ -4548,11 +4607,7 @@ static int fio_channel_cmp(channel_s *ch1, channel_s *ch2) {
|
|
4548
4607
|
!memcmp(ch1->name, ch2->name, ch1->name_len);
|
4549
4608
|
}
|
4550
4609
|
/* pub/sub channels and core data sets have a long life, so avoid fio_malloc */
|
4551
|
-
#
|
4552
|
-
#define FIO_FORCE_MALLOC 1
|
4553
|
-
#define FIO_FORCE_MALLOC_IS_TMP 1
|
4554
|
-
#endif
|
4555
|
-
|
4610
|
+
#define FIO_FORCE_MALLOC_TMP 1
|
4556
4611
|
#define FIO_SET_NAME fio_ch_set
|
4557
4612
|
#define FIO_SET_OBJ_TYPE channel_s *
|
4558
4613
|
#define FIO_SET_OBJ_COMPARE(o1, o2) fio_channel_cmp((o1), (o2))
|
@@ -4560,19 +4615,17 @@ static int fio_channel_cmp(channel_s *ch1, channel_s *ch2) {
|
|
4560
4615
|
#define FIO_SET_OBJ_COPY(dest, src) ((dest) = fio_channel_copy((src)))
|
4561
4616
|
#include <fio.h>
|
4562
4617
|
|
4618
|
+
#define FIO_FORCE_MALLOC_TMP 1
|
4563
4619
|
#define FIO_ARY_NAME fio_meta_ary
|
4564
4620
|
#define FIO_ARY_TYPE fio_msg_metadata_fn
|
4565
4621
|
#include <fio.h>
|
4566
4622
|
|
4623
|
+
#define FIO_FORCE_MALLOC_TMP 1
|
4567
4624
|
#define FIO_SET_NAME fio_engine_set
|
4568
4625
|
#define FIO_SET_OBJ_TYPE fio_pubsub_engine_s *
|
4569
4626
|
#define FIO_SET_OBJ_COMPARE(k1, k2) ((k1) == (k2))
|
4570
4627
|
#include <fio.h>
|
4571
4628
|
|
4572
|
-
#if FIO_FORCE_MALLOC_IS_TMP
|
4573
|
-
#undef FIO_FORCE_MALLOC
|
4574
|
-
#endif
|
4575
|
-
|
4576
4629
|
struct fio_collection_s {
|
4577
4630
|
fio_ch_set_s channels;
|
4578
4631
|
fio_lock_i lock;
|
@@ -6823,9 +6876,8 @@ void *fio_realloc2(void *ptr, size_t new_size, size_t copy_length) {
|
|
6823
6876
|
return NULL;
|
6824
6877
|
new_size = ((new_size >> 4) + (!!(new_size & 15)));
|
6825
6878
|
copy_length = ((copy_length >> 4) + (!!(copy_length & 15)));
|
6826
|
-
|
6827
|
-
|
6828
|
-
fio_memcpy(new_mem, ptr, (copy_length > new_size ? new_size : copy_length));
|
6879
|
+
fio_memcpy(new_mem, ptr, copy_length > new_size ? new_size : copy_length);
|
6880
|
+
|
6829
6881
|
block_slice_free(ptr);
|
6830
6882
|
return new_mem;
|
6831
6883
|
zero_size:
|
data/ext/iodine/fio.h
CHANGED
@@ -36,6 +36,7 @@ Feel free to copy, use and enjoy according to the license provided.
|
|
36
36
|
* Cluster / Pub/Sub Middleware and Extensions ("Engines")
|
37
37
|
*
|
38
38
|
* Atomic Operations and Spin Locking Helper Functions
|
39
|
+
* Simple Constant Time Operations
|
39
40
|
* Byte Swapping and Network Order
|
40
41
|
*
|
41
42
|
* Converting Numbers to Strings (and back)
|
@@ -109,7 +110,7 @@ Version and helper macros
|
|
109
110
|
#define FIO_VERSION_MAJOR 0
|
110
111
|
#define FIO_VERSION_MINOR 7
|
111
112
|
#define FIO_VERSION_PATCH 0
|
112
|
-
#define FIO_VERSION_BETA
|
113
|
+
#define FIO_VERSION_BETA 6
|
113
114
|
|
114
115
|
/* Automatically convert version data to a string constant - ignore these two */
|
115
116
|
#define FIO_MACRO2STR_STEP2(macro) #macro
|
@@ -323,16 +324,16 @@ Memory pool / custom allocator for short lived objects
|
|
323
324
|
* Allocates memory using a per-CPU core block memory pool.
|
324
325
|
* Memory is zeroed out.
|
325
326
|
*
|
326
|
-
* Allocations above FIO_MEMORY_BLOCK_ALLOC_LIMIT (
|
327
|
-
*
|
327
|
+
* Allocations above FIO_MEMORY_BLOCK_ALLOC_LIMIT (16Kb when using 32Kb blocks)
|
328
|
+
* will be redirected to `mmap`, as if `fio_mmap` was called.
|
328
329
|
*/
|
329
330
|
void *FIO_ALIGN_NEW fio_malloc(size_t size);
|
330
331
|
|
331
332
|
/**
|
332
333
|
* same as calling `fio_malloc(size_per_unit * unit_count)`;
|
333
334
|
*
|
334
|
-
* Allocations above FIO_MEMORY_BLOCK_ALLOC_LIMIT (
|
335
|
-
*
|
335
|
+
* Allocations above FIO_MEMORY_BLOCK_ALLOC_LIMIT (16Kb when using 32Kb blocks)
|
336
|
+
* will be redirected to `mmap`, as if `fio_mmap` was called.
|
336
337
|
*/
|
337
338
|
void *FIO_ALIGN_NEW fio_calloc(size_t size_per_unit, size_t unit_count);
|
338
339
|
|
@@ -372,22 +373,6 @@ void fio_malloc_after_fork(void);
|
|
372
373
|
|
373
374
|
#undef FIO_ALIGN
|
374
375
|
|
375
|
-
#if FIO_FORCE_MALLOC
|
376
|
-
#define FIO_MALLOC(size) calloc((size), 1)
|
377
|
-
#define FIO_CALLOC(size, units) calloc((size), (units))
|
378
|
-
#define FIO_REALLOC(ptr, new_length, existing_data_length) \
|
379
|
-
realloc((ptr), (new_length))
|
380
|
-
#define FIO_FREE free
|
381
|
-
|
382
|
-
#else
|
383
|
-
#define FIO_MALLOC(size) fio_malloc((size))
|
384
|
-
#define FIO_CALLOC(size, units) fio_calloc((size), (units))
|
385
|
-
#define FIO_REALLOC(ptr, new_length, existing_data_length) \
|
386
|
-
fio_realloc2((ptr), (new_length), (existing_data_length))
|
387
|
-
#define FIO_FREE fio_free
|
388
|
-
|
389
|
-
#endif
|
390
|
-
|
391
376
|
/* *****************************************************************************
|
392
377
|
|
393
378
|
|
@@ -1128,12 +1113,12 @@ inline FIO_FUNC ssize_t fio_write(const intptr_t uuid, const void *buffer,
|
|
1128
1113
|
const size_t length) {
|
1129
1114
|
if (!length || !buffer)
|
1130
1115
|
return 0;
|
1131
|
-
void *cpy =
|
1116
|
+
void *cpy = fio_malloc(length);
|
1132
1117
|
if (!cpy)
|
1133
1118
|
return -1;
|
1134
1119
|
memcpy(cpy, buffer, length);
|
1135
1120
|
return fio_write2(uuid, .data.buffer = cpy, .length = length,
|
1136
|
-
.after.dealloc =
|
1121
|
+
.after.dealloc = fio_free);
|
1137
1122
|
}
|
1138
1123
|
|
1139
1124
|
/**
|
@@ -1322,6 +1307,23 @@ typedef struct fio_rw_hook_s {
|
|
1322
1307
|
/** Sets a socket hook state (a pointer to the struct). */
|
1323
1308
|
int fio_rw_hook_set(intptr_t uuid, fio_rw_hook_s *rw_hooks, void *udata);
|
1324
1309
|
|
1310
|
+
/**
|
1311
|
+
* Replaces an existing read/write hook with another from within a read/write
|
1312
|
+
* hook callback.
|
1313
|
+
*
|
1314
|
+
* Does NOT call any cleanup callbacks.
|
1315
|
+
*
|
1316
|
+
* Replaces existing udata. Call with the existing udata to keep it.
|
1317
|
+
*
|
1318
|
+
* Returns -1 on error, 0 on success.
|
1319
|
+
*
|
1320
|
+
* Note: this function is marked as unsafe, since it should only be called from
|
1321
|
+
* within an existing read/write hook callback. Otherwise, data corruption
|
1322
|
+
* might occur.
|
1323
|
+
*/
|
1324
|
+
int fio_rw_hook_replace_unsafe(intptr_t uuid, fio_rw_hook_s *rw_hooks,
|
1325
|
+
void *udata);
|
1326
|
+
|
1325
1327
|
/** The default Read/Write hooks used for system Read/Write (udata == NULL). */
|
1326
1328
|
extern const fio_rw_hook_s FIO_DEFAULT_RW_HOOKS;
|
1327
1329
|
|
@@ -1983,6 +1985,56 @@ FIO_FUNC inline void fio_throttle_thread(size_t nano_sec);
|
|
1983
1985
|
|
1984
1986
|
|
1985
1987
|
|
1988
|
+
Simple Constant Time Operations
|
1989
|
+
( boolean true / false and if )
|
1990
|
+
|
1991
|
+
|
1992
|
+
|
1993
|
+
|
1994
|
+
|
1995
|
+
|
1996
|
+
|
1997
|
+
|
1998
|
+
|
1999
|
+
|
2000
|
+
|
2001
|
+
***************************************************************************** */
|
2002
|
+
|
2003
|
+
/** Returns 1 if the expression is true (input isn't zero). */
|
2004
|
+
FIO_FUNC inline uintptr_t fio_ct_true(uintptr_t cond) {
|
2005
|
+
// promise that the highest bit is set if any bits are set, than shift.
|
2006
|
+
return ((cond | (0 - cond)) >> ((sizeof(cond) << 3) - 1));
|
2007
|
+
}
|
2008
|
+
|
2009
|
+
/** Returns 1 if the expression is false (input is zero). */
|
2010
|
+
FIO_FUNC inline uintptr_t fio_ct_false(uintptr_t cond) {
|
2011
|
+
// fio_ct_true returns only one bit, XOR will inverse that bit.
|
2012
|
+
return fio_ct_true(cond) ^ 1;
|
2013
|
+
}
|
2014
|
+
|
2015
|
+
/** Returns `a` if `cond` is boolean and true, returns b otherwise. */
|
2016
|
+
FIO_FUNC inline uintptr_t fio_ct_if(uint8_t cond, uintptr_t a, uintptr_t b) {
|
2017
|
+
// b^(a^b) cancels b out. 0-1 => sets all bits.
|
2018
|
+
return (b ^ ((0 - (cond & 1)) & (a ^ b)));
|
2019
|
+
}
|
2020
|
+
|
2021
|
+
/** Returns `a` if `cond` isn't zero (uses fio_ct_true), returns b otherwise. */
|
2022
|
+
FIO_FUNC inline uintptr_t fio_ct_if2(uintptr_t cond, uintptr_t a, uintptr_t b) {
|
2023
|
+
// b^(a^b) cancels b out. 0-1 => sets all bits.
|
2024
|
+
return fio_ct_if(fio_ct_true(cond), a, b);
|
2025
|
+
}
|
2026
|
+
|
2027
|
+
/* *****************************************************************************
|
2028
|
+
|
2029
|
+
|
2030
|
+
|
2031
|
+
|
2032
|
+
|
2033
|
+
|
2034
|
+
|
2035
|
+
|
2036
|
+
|
2037
|
+
|
1986
2038
|
Byte Swapping and Network Order
|
1987
2039
|
(Big Endian v.s Little Endian etc')
|
1988
2040
|
|
@@ -2768,6 +2820,42 @@ FIO_FUNC inline int fio_trylock_dbg(fio_lock_i *lock, const char *file,
|
|
2768
2820
|
|
2769
2821
|
|
2770
2822
|
|
2823
|
+
Memory allocation macros for helper types
|
2824
|
+
|
2825
|
+
|
2826
|
+
|
2827
|
+
|
2828
|
+
|
2829
|
+
|
2830
|
+
***************************************************************************** */
|
2831
|
+
|
2832
|
+
#undef FIO_MALLOC
|
2833
|
+
#undef FIO_CALLOC
|
2834
|
+
#undef FIO_REALLOC
|
2835
|
+
#undef FIO_FREE
|
2836
|
+
|
2837
|
+
#if FIO_FORCE_MALLOC || FIO_FORCE_MALLOC_TMP
|
2838
|
+
#define FIO_MALLOC(size) calloc((size), 1)
|
2839
|
+
#define FIO_CALLOC(size, units) calloc((size), (units))
|
2840
|
+
#define FIO_REALLOC(ptr, new_length, existing_data_length) \
|
2841
|
+
realloc((ptr), (new_length))
|
2842
|
+
#define FIO_FREE free
|
2843
|
+
|
2844
|
+
#else
|
2845
|
+
#define FIO_MALLOC(size) fio_malloc((size))
|
2846
|
+
#define FIO_CALLOC(size, units) fio_calloc((size), (units))
|
2847
|
+
#define FIO_REALLOC(ptr, new_length, existing_data_length) \
|
2848
|
+
fio_realloc2((ptr), (new_length), (existing_data_length))
|
2849
|
+
#define FIO_FREE fio_free
|
2850
|
+
#endif /* FIO_FORCE_MALLOC || FIO_FORCE_MALLOC_TMP */
|
2851
|
+
|
2852
|
+
/* *****************************************************************************
|
2853
|
+
|
2854
|
+
|
2855
|
+
|
2856
|
+
|
2857
|
+
|
2858
|
+
|
2771
2859
|
Linked List Helpers
|
2772
2860
|
|
2773
2861
|
exposes internally used inline helpers for linked lists
|
@@ -2960,7 +3048,7 @@ FIO_FUNC inline void *fio_ls_remove(fio_ls_s *node) {
|
|
2960
3048
|
const void *ret = node->obj;
|
2961
3049
|
node->next->prev = node->prev;
|
2962
3050
|
node->prev->next = node->next;
|
2963
|
-
|
3051
|
+
FIO_FREE(node);
|
2964
3052
|
return (void *)ret;
|
2965
3053
|
}
|
2966
3054
|
|
@@ -2969,11 +3057,8 @@ FIO_FUNC inline fio_ls_s *fio_ls_push(fio_ls_s *pos, const void *obj) {
|
|
2969
3057
|
if (!pos)
|
2970
3058
|
return NULL;
|
2971
3059
|
/* prepare item */
|
2972
|
-
fio_ls_s *item = (fio_ls_s *)
|
2973
|
-
|
2974
|
-
perror("ERROR: simple list couldn't allocate memory");
|
2975
|
-
exit(errno);
|
2976
|
-
}
|
3060
|
+
fio_ls_s *item = (fio_ls_s *)FIO_MALLOC(sizeof(*item));
|
3061
|
+
FIO_ASSERT_ALLOC(item);
|
2977
3062
|
*item = (fio_ls_s){.prev = pos->prev, .next = pos, .obj = obj};
|
2978
3063
|
/* inject item */
|
2979
3064
|
pos->prev->next = item;
|
@@ -3105,15 +3190,20 @@ typedef struct {
|
|
3105
3190
|
.dealloc = FIO_FREE})
|
3106
3191
|
|
3107
3192
|
/**
|
3108
|
-
* This macro allows the container to be initialized with existing data,
|
3109
|
-
*
|
3110
|
-
*
|
3111
|
-
* The `capacity` value should exclude the NUL character (if exists).
|
3193
|
+
* This macro allows the container to be initialized with existing static data,
|
3194
|
+
* that shouldn't be freed.
|
3112
3195
|
*/
|
3113
3196
|
#define FIO_STR_INIT_STATIC(buffer) \
|
3114
3197
|
((fio_str_s){ \
|
3115
3198
|
.data = (char *)(buffer), .len = strlen((buffer)), .dealloc = NULL})
|
3116
3199
|
|
3200
|
+
/**
|
3201
|
+
* This macro allows the container to be initialized with existing static data,
|
3202
|
+
* that shouldn't be freed.
|
3203
|
+
*/
|
3204
|
+
#define FIO_STR_INIT_STATIC2(buffer, length) \
|
3205
|
+
((fio_str_s){.data = (char *)(buffer), .len = (length), .dealloc = NULL})
|
3206
|
+
|
3117
3207
|
/**
|
3118
3208
|
* Allocates a new fio_str_s object on the heap and initializes it.
|
3119
3209
|
*
|
@@ -3629,10 +3719,6 @@ String Implementation - Memory management
|
|
3629
3719
|
* directly to `mmap` (due to their size, usually over 12KB).
|
3630
3720
|
*/
|
3631
3721
|
#define ROUND_UP_CAPA2WORDS(num) (((num) + 1) | (sizeof(long double) - 1))
|
3632
|
-
// Smaller might be:
|
3633
|
-
// ((((num) + 1) & (sizeof(long double) - 1))
|
3634
|
-
// ? (((num) + 1) | (sizeof(long double) - 1))
|
3635
|
-
// : (num))
|
3636
3722
|
|
3637
3723
|
/**
|
3638
3724
|
* Requires the String to have at least `needed` capacity. Returns the current
|
@@ -5908,5 +5994,6 @@ restart:
|
|
5908
5994
|
#undef FIO_NAME_FROM_MACRO_STEP3
|
5909
5995
|
#undef FIO_NAME_FREE
|
5910
5996
|
#undef FIO_SET_NAME
|
5997
|
+
#undef FIO_FORCE_MALLOC_TMP
|
5911
5998
|
|
5912
5999
|
#endif
|