iodine 0.7.14 → 0.7.15
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/CHANGELOG.md +12 -0
- data/README.md +9 -8
- data/SPEC-PubSub-Draft.md +26 -22
- data/SPEC-Websocket-Draft.md +4 -4
- data/examples/sub-protocols.ru +90 -0
- data/exe/iodine +3 -1
- data/ext/iodine/fio.c +103 -69
- data/ext/iodine/fio.h +1 -1
- data/ext/iodine/fio_cli.c +26 -18
- data/ext/iodine/fio_cli.h +3 -1
- data/ext/iodine/fiobj_data.c +6 -1
- data/ext/iodine/fiobj_mustache.c +69 -13
- data/ext/iodine/http.c +26 -11
- data/ext/iodine/http1.c +3 -3
- data/ext/iodine/http_mime_parser.h +9 -0
- data/ext/iodine/iodine.c +34 -16
- data/ext/iodine/iodine_mustache.c +0 -65
- data/ext/iodine/iodine_pubsub.c +0 -1
- data/ext/iodine/mustache_parser.h +40 -14
- data/lib/iodine.rb +16 -8
- data/lib/iodine/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f1996d0474dc00ad0614035f36b703154b594415278cd18624cec94c8149150e
|
4
|
+
data.tar.gz: 3060659e07df3fc734594584b407b5bf9156ae77fcdb8709f62a49d0f2f62296
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2ab1733a97c6617232022405bd25d4f0c46d4a99c6751b5a8467e48fa17efc0dc815dc47ca329c7ca955d135c56e8a06c69d3fd168ead0b3510712e909711468
|
7
|
+
data.tar.gz: 53be4c7971bca24fd484bfa4dd18d67a99ffba196a5908c76bf1a3001a957ef607c51ec8d90b3d4714d6297609bf4dde8077d24bd85eee081b875bf27faa5d8f
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,18 @@ 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.15
|
10
|
+
|
11
|
+
**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).
|
12
|
+
|
13
|
+
**Fix**: (`fio`) fixed superfluous and potentially erroneous pub/sub engine callback calls to `unsubscribe`, caused by (mistakingly) reporting filter channel closure.
|
14
|
+
|
15
|
+
**Fix**: (`http/1.1`) avoid processing further requests if the connection was closed.
|
16
|
+
|
17
|
+
**Fix**: (`iodine`) fixed some errors in the documentation and added a missing deprecation notice.
|
18
|
+
|
19
|
+
**Update**: (`fio`) updated the automatic concurrency calculations to leave resources for the system when a negative value is provided (was only available for worker count calculations, now available for thread count as well).
|
20
|
+
|
9
21
|
#### Change log v.0.7.14
|
10
22
|
|
11
23
|
**Fix**: (`facil.io`) fixed superfluous ping event.
|
data/README.md
CHANGED
@@ -507,25 +507,26 @@ require 'iodine'
|
|
507
507
|
|
508
508
|
# an echo protocol with asynchronous notifications.
|
509
509
|
class EchoProtocol
|
510
|
-
# `on_message` is
|
511
|
-
# `on_message` has a 1Kb buffer that recycles itself for memory optimization.
|
510
|
+
# `on_message` is called when data is available.
|
512
511
|
def on_message client, buffer
|
513
512
|
# writing will never block and will use a buffer written in C when needed.
|
514
513
|
client.write buffer
|
515
514
|
# close will be performed only once all the data in the write buffer
|
516
515
|
# was sent. use `force_close` to close early.
|
517
516
|
client.close if buffer =~ /^bye[\r\n]/i
|
518
|
-
# run asynchronous tasks
|
519
|
-
Iodine.
|
520
|
-
|
521
|
-
|
517
|
+
# run asynchronous tasks... after a set number of milliseconds
|
518
|
+
Iodine.run_after(1000) do
|
519
|
+
# or schedule the task immediately
|
520
|
+
Iodine.run do
|
521
|
+
puts "Echoed data: #{buffer}"
|
522
|
+
end
|
522
523
|
end
|
523
524
|
end
|
524
525
|
end
|
525
526
|
|
526
527
|
# listen on port 3000 for the echo protocol.
|
527
528
|
Iodine.listen(port: "3000") { EchoProtocol.new }
|
528
|
-
Iodine.threads =
|
529
|
+
Iodine.threads = 1
|
529
530
|
Iodine.workers = 1
|
530
531
|
Iodine.start
|
531
532
|
```
|
@@ -565,7 +566,7 @@ class ChatProtocol
|
|
565
566
|
end
|
566
567
|
end
|
567
568
|
|
568
|
-
#an initial login protocol
|
569
|
+
# an initial login protocol
|
569
570
|
class LoginProtocol
|
570
571
|
def on_open client
|
571
572
|
client.write "Enter nickname to log in to chat room:\n"
|
data/SPEC-PubSub-Draft.md
CHANGED
@@ -20,7 +20,7 @@ Conforming Pub/Sub implementations **MUST** implement the following pub/sub rela
|
|
20
20
|
|
21
21
|
* `:match` indicates a matching algorithm should be applied to the `to` variable (`to` is a pattern).
|
22
22
|
|
23
|
-
Possible values should include [`:redis`](https://github.com/antirez/redis/blob/398b2084af067ae4d669e0ce5a63d3bc89c639d3/src/util.c#L46-L167), [`:nats`](https://nats.io/documentation/faq/#wildcards) or [`:rabbitmq`](https://www.rabbitmq.com/tutorials/tutorial-five-ruby.html). Pub/Sub implementations *MAY* support none, some or all of these common pattern resolution schemes.
|
23
|
+
Possible (suggested) values should include [`:redis`](https://github.com/antirez/redis/blob/398b2084af067ae4d669e0ce5a63d3bc89c639d3/src/util.c#L46-L167), [`:nats`](https://nats.io/documentation/faq/#wildcards) or [`:rabbitmq`](https://www.rabbitmq.com/tutorials/tutorial-five-ruby.html). Pub/Sub implementations *MAY* support none, some or all of these common pattern resolution schemes.
|
24
24
|
|
25
25
|
* `:handler` is an alternative to the optional block. It should accept Proc like objects (objects that answer to `.call(from, msg)`).
|
26
26
|
|
@@ -31,7 +31,9 @@ Conforming Pub/Sub implementations **MUST** implement the following pub/sub rela
|
|
31
31
|
This option is only valid if the optional `block` is missing and the connection is a WebSocket connection. Note that SSE connections are limited to text data by design.
|
32
32
|
|
33
33
|
This will dictate the encoding for outgoing WebSocket message when publications are directly sent to the client (as a text message or a binary blob). `:text` will be the default value for a missing `:as` option.
|
34
|
-
|
34
|
+
|
35
|
+
Servers *MAY* ignore this value if they set the message type (text/binary) based on UTF-8 validation.
|
36
|
+
|
35
37
|
If a subscription to `to` already exists, it should be *replaced* by the new subscription (the old subscription should be canceled / unsubscribed).
|
36
38
|
|
37
39
|
When the `subscribe` method is called within a WebSocket / SSE Callback object, the subscription must be closed automatically when the connection is closed.
|
@@ -50,64 +52,66 @@ Conforming Pub/Sub implementations **MUST** implement the following pub/sub rela
|
|
50
52
|
|
51
53
|
* `message` a String with containing the data to be published.
|
52
54
|
|
53
|
-
* `engine`
|
55
|
+
* `engine` routes the publish method to the specified Pub/Sub Engine (see later on). If none is specified, the default engine should be used. If `false` is specified, the message should be forwarded to all subscribed clients.
|
54
56
|
|
55
57
|
The `publish` method must return `true` if a publication was scheduled (not necessarily performed). If it's already known that the publication would fail, the method should return `false`.
|
56
58
|
|
57
59
|
An implementation **MUST** call the relevant PubSubEngine's `publish` method after performing any internal book keeping logic. If `engine` is `nil`, the default PubSubEngine should be called. If `engine` is `false`, the implementation **MUST** forward the published message to the actual clients (if any).
|
58
60
|
|
59
|
-
A global alias for this method (allowing it to be accessed from outside active connections)
|
61
|
+
A global alias for this method (allowing it to be accessed from outside active connections) **MAY** be defined as `Rack::PubSub.publish`.
|
60
62
|
|
61
|
-
Implementations **MUST** implement the following methods:
|
63
|
+
Implementations **MUST** implement the following methods in one of their public classes / modules (iodine implements these under `Iodine::PubSub`):
|
62
64
|
|
63
|
-
* `
|
65
|
+
* `attach(engine)` where `engine` is a `PubSubEngine` object, as described in this specification.
|
64
66
|
|
65
|
-
When a pub/sub engine is
|
67
|
+
When a pub/sub engine is attached, the implementation **MUST** inform the engine of any existing or future subscriptions.
|
66
68
|
|
67
69
|
The implementation **MUST** call the engine's `subscribe` callback for each existing (and future) subscription.
|
68
70
|
|
69
|
-
|
71
|
+
The implementation **MUST** allow multiple "engines" to be attached when multiple calls to `attach` are made.
|
72
|
+
|
73
|
+
* `detach(engine)` where `engine` is a PubSubEngine object as described in this specification.
|
70
74
|
|
71
|
-
Removes an engine from the pub/sub
|
75
|
+
Removes an engine from the pub/sub system. The opposite of `attach`.
|
72
76
|
|
73
|
-
* `
|
77
|
+
* `default = engine` sets a default pub/sub engine, where `engine` is a PubSubEngine object as described in this specification.
|
74
78
|
|
75
|
-
Implementations **MUST** forward any `publish` method calls to the default pub/sub engine.
|
79
|
+
Implementations **MUST** forward any `publish` method calls to the default pub/sub engine, unless an `engine` is specified in arguments passes to the `publish` method.
|
76
80
|
|
77
|
-
* `
|
81
|
+
* `default` returns the current default pub/sub engine, where the engine is a PubSubEngine object as described in this specification.
|
78
82
|
|
79
|
-
* `
|
83
|
+
* `reset(engine)` where `engine` is a PubSubEngine object as described in this specification.
|
80
84
|
|
81
85
|
Implementations **MUST** behave as if the engine was newly registered and (re)inform the engine of any existing subscriptions by calling engine's `subscribe` callback for each existing subscription.
|
82
86
|
|
83
|
-
Implementations **MAY** implement pub/sub internally (in which case the `
|
87
|
+
Implementations **MAY** implement pub/sub internally (in which case the `default` engine is the server itself or a server's module).
|
84
88
|
|
85
89
|
However, servers **MUST** support external pub/sub "engines" as described above, using PubSubEngine objects.
|
86
90
|
|
87
|
-
PubSubEngine objects **MUST** implement the following methods:
|
91
|
+
`PubSubEngine` objects **MUST** implement the following methods:
|
88
92
|
|
89
|
-
* `subscribe(channel,
|
93
|
+
* `subscribe(channel, match=nil)` this method performs the subscription to the specified channel.
|
90
94
|
|
91
|
-
If `
|
95
|
+
If `match` is a Symbol that the engine recognizes (i.e., `:redis`, `:nats`, etc'), the engine should behave accordingly. i.e., the value `:redis` on a Redis engine will invoke the PSUBSCRIBE Redis command.
|
92
96
|
|
93
97
|
The method must return `true` if a subscription was scheduled (or performed) or `false` if the subscription is known to fail.
|
94
98
|
|
95
99
|
This method will be called by the server (for each registered engine). The engine may assume that the method would never be called directly by an application.
|
96
100
|
|
97
|
-
* `unsubscribe(channel,
|
101
|
+
* `unsubscribe(channel, match=nil)` this method performs closes the subscription to the specified channel.
|
98
102
|
|
99
103
|
The method's semantics are similar to `subscribe`.
|
100
104
|
|
101
105
|
This method will be called by the server (for each registered engine). The engine may assume that the method would never be called directly by an application.
|
102
106
|
|
103
|
-
* `publish(channel, message)` where both `channel` and `message` are String
|
107
|
+
* `publish(channel, message)` where both `channel` and `message` are String objects.
|
104
108
|
|
105
109
|
This method will be called by the server when a message is published using the engine.
|
106
110
|
|
107
|
-
The engine **MUST** assume that the method might called directly by an application.
|
111
|
+
The engine **MUST** assume that the method might get called directly by an application.
|
108
112
|
|
109
|
-
When a PubSubEngine object receives a published message, it should call:
|
113
|
+
When a PubSubEngine object receives a published message, it *should* call:
|
110
114
|
|
111
115
|
```ruby
|
112
|
-
|
116
|
+
Foo::PubSub.publish channel, message, false
|
113
117
|
```
|
data/SPEC-Websocket-Draft.md
CHANGED
@@ -13,9 +13,9 @@ The purpose of these specifications is:
|
|
13
13
|
|
14
14
|
Simply put, when choosing between conforming servers, the application doesn’t need to have any knowledge about the chosen server.
|
15
15
|
|
16
|
-
2. To
|
16
|
+
2. To support “native" (server-side) WebSocket and EventSource (SSE) connections and using application side callbacks.
|
17
17
|
|
18
|
-
Simply put, to make it easy for applications to accept WebSocket and EventSource (SSE) connections from WebSocket and EventSource clients (commonly browsers).
|
18
|
+
Simply put, to make it easy for applications to accept WebSocket and EventSource (SSE) connections from WebSocket and EventSource clients (commonly browsers) while abstracting away any transport layer details.
|
19
19
|
|
20
20
|
3. Allow applications to use WebSocket and EventSource (SSE) on HTTP/2 servers. Note: current `hijack` practices will break network connections when attempting to implement EventSource (SSE).
|
21
21
|
|
@@ -45,11 +45,11 @@ The Callback Object could be a any object which implements any of the following
|
|
45
45
|
|
46
46
|
Servers **MAY**, optionally, implement a **recyclable buffer** for the `on_message` callback. However, this is optional and it is *not* required.
|
47
47
|
|
48
|
-
* `on_drained(client)` **MAY** be called when the the `write` buffer becomes empty. **If** `pending` returns a non-zero value, the `on_drained` callback **MUST** be called once the write buffer becomes empty.
|
48
|
+
* `on_drained(client)` **MAY** be called when the the `client.write` buffer becomes empty. **If** `client.pending` returns a non-zero value, the `on_drained` callback **MUST** be called once the write buffer becomes empty.
|
49
49
|
|
50
50
|
* `on_shutdown(client)` **MAY** be called during the server's graceful shutdown process, _before_ the connection is closed and in addition to the `on_close` function (which is called _after_ the connection is closed.
|
51
51
|
|
52
|
-
* `on_close(client)` **MUST** be called _after_ the connection was closed for whatever reason (socket errors, parsing errors, timeouts, client disconnection, `close` being called, etc').
|
52
|
+
* `on_close(client)` **MUST** be called _after_ the connection was closed for whatever reason (socket errors, parsing errors, timeouts, client disconnection, `client.close` being called, etc').
|
53
53
|
|
54
54
|
|
55
55
|
The server **MUST** provide the Callback Object with a `client` object, that supports the following methods (this approach promises applications could be server agnostic):
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# This is a WebSocket / SSE notification example application.
|
4
|
+
#
|
5
|
+
# In this example, WebSocket sub-protocols are explored.
|
6
|
+
#
|
7
|
+
# Running this application from the command line is easy with:
|
8
|
+
#
|
9
|
+
# iodine
|
10
|
+
#
|
11
|
+
# Or, in a single thread and a single process:
|
12
|
+
#
|
13
|
+
# iodine -t 1 -w 1
|
14
|
+
#
|
15
|
+
# Test using:
|
16
|
+
#
|
17
|
+
# var subprotocol = "echo"; // or "chat"
|
18
|
+
# ws = new WebSocket("ws://localhost:3000/Mitchel", subprotocol);
|
19
|
+
# ws.onmessage = function(e) { console.log(e.data); };
|
20
|
+
# ws.onclose = function(e) { console.log("Closed"); };
|
21
|
+
# ws.onopen = function(e) { e.target.send("Yo!"); };
|
22
|
+
|
23
|
+
|
24
|
+
# Chat clients connect with the "chat" sub-protocol.
|
25
|
+
class ChatClient
|
26
|
+
def on_open client
|
27
|
+
@nickname = client.env['PATH_INFO'].to_s.split('/')[1] || "Guest"
|
28
|
+
client.subscribe :chat
|
29
|
+
client.publish :chat , "#{@nickname} joined the chat."
|
30
|
+
end
|
31
|
+
def on_close client
|
32
|
+
client.publish :chat , "#{@nickname} left the chat."
|
33
|
+
end
|
34
|
+
def on_shutdown client
|
35
|
+
client.write "Server is shutting down... disconnecting all clients. Goodbye."
|
36
|
+
end
|
37
|
+
def on_message client, message
|
38
|
+
client.publish :chat , "#{@nickname}: #{message}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Echo clients connect with the "echo" sub-protocol.
|
43
|
+
class EchoClient
|
44
|
+
def on_open client
|
45
|
+
client.write "You established an echo connection."
|
46
|
+
end
|
47
|
+
def on_shutdown client
|
48
|
+
client.write "Server is shutting down... goodbye."
|
49
|
+
end
|
50
|
+
def on_message client, message
|
51
|
+
client.write message
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Rack application module
|
56
|
+
module APP
|
57
|
+
# the allowed protocols
|
58
|
+
CHAT_PROTOCOL_NAME = "chat"
|
59
|
+
ECHO_PROTOCOL_NAME = "echo"
|
60
|
+
PROTOCOLS =[CHAT_PROTOCOL_NAME, ECHO_PROTOCOL_NAME]
|
61
|
+
|
62
|
+
# the Rack application
|
63
|
+
def call env
|
64
|
+
return [200, {}, ["Hello World"]] unless env["rack.upgrade?"]
|
65
|
+
protocol = select_protocol(env)
|
66
|
+
case(protocol)
|
67
|
+
when CHAT_PROTOCOL_NAME
|
68
|
+
env["rack.upgrade"] = ChatClient.new
|
69
|
+
[101, { "Sec-Websocket-Protocol" => protocol }, []]
|
70
|
+
when ECHO_PROTOCOL_NAME
|
71
|
+
env["rack.upgrade"] = EchoClient.new
|
72
|
+
[101, { "Sec-Websocket-Protocol" => protocol }, []]
|
73
|
+
else
|
74
|
+
[400, {}, ["Unsupported protocol specified"]]
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def select_protocol(env)
|
79
|
+
request_protocols = env["HTTP_SEC_WEBSOCKET_PROTOCOL"]
|
80
|
+
unless request_protocols.nil?
|
81
|
+
request_protocols = request_protocols.split(/,\s?/) if request_protocols.is_a?(String)
|
82
|
+
request_protocols.detect { |request_protocol| PROTOCOLS.include? request_protocol }
|
83
|
+
end # either `nil` or the result of `request_protocols.detect` are returned
|
84
|
+
end
|
85
|
+
|
86
|
+
# make functions availble as singleton module
|
87
|
+
extend self
|
88
|
+
end
|
89
|
+
|
90
|
+
run APP
|
data/exe/iodine
CHANGED
@@ -33,7 +33,9 @@ module Iodine
|
|
33
33
|
puts " Running only static file service."
|
34
34
|
opt = ::Rack::Server::Options.new.parse!([])
|
35
35
|
else
|
36
|
-
puts
|
36
|
+
puts "\nERROR: Couldn't run Ruby application, check command line arguments."
|
37
|
+
ARGV << "-?"
|
38
|
+
Iodine::Base::CLI.parse
|
37
39
|
exit(0);
|
38
40
|
end
|
39
41
|
end
|
data/ext/iodine/fio.c
CHANGED
@@ -1456,26 +1456,35 @@ void fio_expected_concurrency(int16_t *threads, int16_t *processes) {
|
|
1456
1456
|
/* Set any option that is less than 0 be equal to cores/value */
|
1457
1457
|
/* Set any option equal to 0 be equal to the other option in value */
|
1458
1458
|
ssize_t cpu_count = fio_detect_cpu_cores();
|
1459
|
-
size_t
|
1459
|
+
size_t thread_cpu_adjust = (*threads <= 0 ? 1 : 0);
|
1460
|
+
size_t worker_cpu_adjust = (*processes <= 0 ? 1 : 0);
|
1460
1461
|
|
1461
1462
|
if (cpu_count > 0) {
|
1462
|
-
int16_t
|
1463
|
+
int16_t tmp = 0;
|
1463
1464
|
if (*threads < 0)
|
1464
|
-
|
1465
|
-
else if (*threads == 0)
|
1466
|
-
|
1467
|
-
|
1468
|
-
|
1465
|
+
tmp = (int16_t)(cpu_count / (*threads * -1));
|
1466
|
+
else if (*threads == 0) {
|
1467
|
+
tmp = -1 * *processes;
|
1468
|
+
thread_cpu_adjust = 0;
|
1469
|
+
} else
|
1470
|
+
tmp = *threads;
|
1469
1471
|
if (*processes < 0)
|
1470
1472
|
*processes = (int16_t)(cpu_count / (*processes * -1));
|
1471
|
-
else if (*processes == 0)
|
1473
|
+
else if (*processes == 0) {
|
1472
1474
|
*processes = -1 * *threads;
|
1473
|
-
|
1474
|
-
|
1475
|
+
worker_cpu_adjust = 0;
|
1476
|
+
}
|
1477
|
+
*threads = tmp;
|
1478
|
+
tmp = *processes;
|
1479
|
+
if (worker_cpu_adjust && (*processes * *threads) >= cpu_count &&
|
1475
1480
|
cpu_count > 3) {
|
1476
|
-
/* leave a
|
1481
|
+
/* leave a resources available for the kernel */
|
1477
1482
|
--*processes;
|
1478
1483
|
}
|
1484
|
+
if (thread_cpu_adjust && (*threads * tmp) >= cpu_count && cpu_count > 3) {
|
1485
|
+
/* leave a resources available for the kernel */
|
1486
|
+
--*threads;
|
1487
|
+
}
|
1479
1488
|
}
|
1480
1489
|
}
|
1481
1490
|
|
@@ -2334,11 +2343,12 @@ static intptr_t fio_unix_socket(const char *address, uint8_t server) {
|
|
2334
2343
|
if (server) {
|
2335
2344
|
unlink(addr.sun_path);
|
2336
2345
|
if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
|
2346
|
+
// perror("couldn't bind unix socket");
|
2337
2347
|
close(fd);
|
2338
2348
|
return -1;
|
2339
2349
|
}
|
2340
2350
|
if (listen(fd, SOMAXCONN) < 0) {
|
2341
|
-
// perror("couldn't start listening");
|
2351
|
+
// perror("couldn't start listening to unix socket");
|
2342
2352
|
close(fd);
|
2343
2353
|
return -1;
|
2344
2354
|
}
|
@@ -4923,7 +4933,7 @@ void fio_unsubscribe(subscription_s *s) {
|
|
4923
4933
|
/* test again within lock */
|
4924
4934
|
if (fio_ls_embd_is_empty(&ch->subscriptions)) {
|
4925
4935
|
fio_ch_set_remove(&c->channels, hashed, ch, NULL);
|
4926
|
-
removed =
|
4936
|
+
removed = (c != &fio_postoffice.filters);
|
4927
4937
|
}
|
4928
4938
|
fio_unlock(&c->lock);
|
4929
4939
|
}
|
@@ -5220,7 +5230,7 @@ static void fio_publish2process(fio_msg_internal_s *m) {
|
|
5220
5230
|
if (m->filter) {
|
5221
5231
|
ch = fio_filter_find_dup(m->filter);
|
5222
5232
|
if (!ch) {
|
5223
|
-
|
5233
|
+
goto finish;
|
5224
5234
|
}
|
5225
5235
|
} else {
|
5226
5236
|
ch = fio_channel_find_dup(m->channel);
|
@@ -5248,6 +5258,7 @@ static void fio_publish2process(fio_msg_internal_s *m) {
|
|
5248
5258
|
}
|
5249
5259
|
fio_unlock(&fio_postoffice.patterns.lock);
|
5250
5260
|
}
|
5261
|
+
finish:
|
5251
5262
|
fio_msg_internal_free(m);
|
5252
5263
|
}
|
5253
5264
|
|
@@ -5268,6 +5279,8 @@ static void fio_publish2process(fio_msg_internal_s *m) {
|
|
5268
5279
|
#define FIO_SET_OBJ_DESTROY(obj) fio_unsubscribe(obj)
|
5269
5280
|
#include <fio.h>
|
5270
5281
|
|
5282
|
+
#define FIO_CLUSTER_NAME_LIMIT 255
|
5283
|
+
|
5271
5284
|
typedef struct cluster_pr_s {
|
5272
5285
|
fio_protocol_s protocol;
|
5273
5286
|
fio_msg_internal_s *msg;
|
@@ -5289,7 +5302,7 @@ static struct cluster_data_s {
|
|
5289
5302
|
intptr_t uuid;
|
5290
5303
|
fio_ls_s clients;
|
5291
5304
|
fio_lock_i lock;
|
5292
|
-
char name[
|
5305
|
+
char name[FIO_CLUSTER_NAME_LIMIT + 1];
|
5293
5306
|
} cluster_data = {.clients = FIO_LS_INIT(cluster_data.clients),
|
5294
5307
|
.lock = FIO_LOCK_INIT};
|
5295
5308
|
|
@@ -5306,10 +5319,9 @@ static void fio_cluster_data_cleanup(int delete_file) {
|
|
5306
5319
|
fio_close(uuid);
|
5307
5320
|
}
|
5308
5321
|
}
|
5309
|
-
cluster_data =
|
5310
|
-
|
5311
|
-
|
5312
|
-
};
|
5322
|
+
cluster_data.uuid = 0;
|
5323
|
+
cluster_data.lock = FIO_LOCK_INIT;
|
5324
|
+
cluster_data.clients = (fio_ls_s)FIO_LS_INIT(cluster_data.clients);
|
5313
5325
|
}
|
5314
5326
|
|
5315
5327
|
static void fio_cluster_cleanup(void *ignore) {
|
@@ -5323,7 +5335,8 @@ static void fio_cluster_init(void) {
|
|
5323
5335
|
/* create a unique socket name */
|
5324
5336
|
char *tmp_folder = getenv("TMPDIR");
|
5325
5337
|
uint32_t tmp_folder_len = 0;
|
5326
|
-
if (!tmp_folder || ((tmp_folder_len = (uint32_t)strlen(tmp_folder)) >
|
5338
|
+
if (!tmp_folder || ((tmp_folder_len = (uint32_t)strlen(tmp_folder)) >
|
5339
|
+
(FIO_CLUSTER_NAME_LIMIT - 28))) {
|
5327
5340
|
#ifdef P_tmpdir
|
5328
5341
|
tmp_folder = (char *)P_tmpdir;
|
5329
5342
|
if (tmp_folder)
|
@@ -5333,7 +5346,7 @@ static void fio_cluster_init(void) {
|
|
5333
5346
|
tmp_folder_len = 5;
|
5334
5347
|
#endif
|
5335
5348
|
}
|
5336
|
-
if (tmp_folder_len >=
|
5349
|
+
if (tmp_folder_len >= (FIO_CLUSTER_NAME_LIMIT - 28)) {
|
5337
5350
|
tmp_folder_len = 0;
|
5338
5351
|
}
|
5339
5352
|
if (tmp_folder_len) {
|
@@ -5343,8 +5356,9 @@ static void fio_cluster_init(void) {
|
|
5343
5356
|
}
|
5344
5357
|
memcpy(cluster_data.name + tmp_folder_len, "facil-io-sock-", 14);
|
5345
5358
|
tmp_folder_len += 14;
|
5346
|
-
tmp_folder_len +=
|
5347
|
-
|
5359
|
+
tmp_folder_len +=
|
5360
|
+
snprintf(cluster_data.name + tmp_folder_len,
|
5361
|
+
FIO_CLUSTER_NAME_LIMIT - tmp_folder_len, "%d", getpid());
|
5348
5362
|
cluster_data.name[tmp_folder_len] = 0;
|
5349
5363
|
|
5350
5364
|
/* remove if existing */
|
@@ -5505,6 +5519,7 @@ static void fio_cluster_on_close(intptr_t uuid, fio_protocol_s *pr_) {
|
|
5505
5519
|
if (c->msg)
|
5506
5520
|
fio_msg_internal_free(c->msg);
|
5507
5521
|
c->msg = NULL;
|
5522
|
+
fio_sub_hash_free(&c->pubsub);
|
5508
5523
|
fio_cluster_protocol_free(c);
|
5509
5524
|
(void)uuid;
|
5510
5525
|
}
|
@@ -5659,7 +5674,6 @@ static void fio_cluster_listen_on_close(intptr_t uuid,
|
|
5659
5674
|
static void fio_listen2cluster(void *ignore) {
|
5660
5675
|
/* this is called for each `fork`, but we only need this to run once. */
|
5661
5676
|
fio_lock(&cluster_data.lock);
|
5662
|
-
fio_cluster_init();
|
5663
5677
|
cluster_data.uuid = fio_socket(cluster_data.name, NULL, 1);
|
5664
5678
|
fio_unlock(&cluster_data.lock);
|
5665
5679
|
if (cluster_data.uuid < 0) {
|
@@ -6671,8 +6685,10 @@ Allocator Initialization (initialize arenas and allocate a block for each CPU)
|
|
6671
6685
|
#if DEBUG
|
6672
6686
|
void fio_memory_dump_missing(void) {
|
6673
6687
|
fprintf(stderr, "\n ==== Attempting Memory Dump (will crash) ====\n");
|
6674
|
-
if (
|
6688
|
+
if (fio_ls_embd_is_empty(&memory.available)) {
|
6689
|
+
fprintf(stderr, "- Memory dump attempt canceled\n");
|
6675
6690
|
return;
|
6691
|
+
}
|
6676
6692
|
block_node_s *smallest =
|
6677
6693
|
FIO_LS_EMBD_OBJ(block_node_s, node, memory.available.next);
|
6678
6694
|
FIO_LS_EMBD_FOR(&memory.available, node) {
|
@@ -6732,8 +6748,11 @@ static void fio_mem_destroy(void) {
|
|
6732
6748
|
FIO_MEMORY_PRINT_BLOCK_STAT_END();
|
6733
6749
|
size_t count = 0;
|
6734
6750
|
FIO_LS_EMBD_FOR(&memory.available, node) { ++count; }
|
6735
|
-
FIO_LOG_DEBUG("Memory pool
|
6736
|
-
(size_t)FIO_MEMORY_BLOCKS_PER_ALLOCATION);
|
6751
|
+
FIO_LOG_DEBUG("Memory blocks in pool: %zu (%zu blocks per allocation).",
|
6752
|
+
count, (size_t)FIO_MEMORY_BLOCKS_PER_ALLOCATION);
|
6753
|
+
#if FIO_MEM_DUMP
|
6754
|
+
fio_memory_dump_missing();
|
6755
|
+
#endif
|
6737
6756
|
}
|
6738
6757
|
big_free(arenas);
|
6739
6758
|
arenas = NULL;
|
@@ -8545,7 +8564,7 @@ Testing Memory Allocator
|
|
8545
8564
|
#define fio_malloc_test() \
|
8546
8565
|
fprintf(stderr, "\n=== SKIPPED facil.io memory allocator (bypassed)\n");
|
8547
8566
|
#else
|
8548
|
-
void fio_malloc_test(void) {
|
8567
|
+
FIO_FUNC void fio_malloc_test(void) {
|
8549
8568
|
fprintf(stderr, "\n=== Testing facil.io memory allocator's system calls\n");
|
8550
8569
|
char *mem = sys_alloc(FIO_MEMORY_BLOCK_SIZE, 0);
|
8551
8570
|
FIO_ASSERT(mem, "sys_alloc failed to allocate memory!\n");
|
@@ -8558,7 +8577,7 @@ void fio_malloc_test(void) {
|
|
8558
8577
|
sys_realloc(mem, FIO_MEMORY_BLOCK_SIZE, FIO_MEMORY_BLOCK_SIZE * 2);
|
8559
8578
|
if (mem == mem2)
|
8560
8579
|
fprintf(stderr, "* Performed system realloc without copy :-)\n");
|
8561
|
-
FIO_ASSERT(mem2[0]
|
8580
|
+
FIO_ASSERT(mem2[0] == 'a' && mem2[FIO_MEMORY_BLOCK_SIZE - 1] == 'z',
|
8562
8581
|
"Reaclloc data was lost!");
|
8563
8582
|
sys_free(mem2, FIO_MEMORY_BLOCK_SIZE * 2);
|
8564
8583
|
fprintf(stderr, "=== Testing facil.io memory allocator's internal data.\n");
|
@@ -8572,8 +8591,10 @@ void fio_malloc_test(void) {
|
|
8572
8591
|
mem[0] = 'a';
|
8573
8592
|
FIO_ASSERT(mem[0] == 'a', "allocate memory wasn't written to!\n");
|
8574
8593
|
mem = fio_realloc(mem, 1);
|
8594
|
+
FIO_ASSERT(mem, "fio_realloc failed!\n");
|
8575
8595
|
FIO_ASSERT(mem[0] == 'a', "fio_realloc memory wasn't copied!\n");
|
8576
8596
|
FIO_ASSERT(arena_last_used, "arena_last_used wasn't initialized!\n");
|
8597
|
+
fio_free(mem);
|
8577
8598
|
block_s *b = arena_last_used->block;
|
8578
8599
|
|
8579
8600
|
/* move arena to block's start */
|
@@ -8639,7 +8660,9 @@ void fio_malloc_test(void) {
|
|
8639
8660
|
++count;
|
8640
8661
|
} while (arena_last_used->block == b);
|
8641
8662
|
|
8663
|
+
mem2 = mem;
|
8642
8664
|
mem = fio_calloc(FIO_MEMORY_BLOCK_ALLOC_LIMIT - 64, 1);
|
8665
|
+
fio_free(mem2);
|
8643
8666
|
FIO_ASSERT(mem,
|
8644
8667
|
"failed to allocate FIO_MEMORY_BLOCK_ALLOC_LIMIT - 64 bytes!\n");
|
8645
8668
|
FIO_ASSERT(((uintptr_t)mem & FIO_MEMORY_BLOCK_MASK) != 16,
|
@@ -8669,11 +8692,18 @@ void fio_malloc_test(void) {
|
|
8669
8692
|
void *m0 = fio_malloc(0);
|
8670
8693
|
void *rm0 = fio_realloc(m0, 16);
|
8671
8694
|
FIO_ASSERT(m0 != rm0, "fio_realloc(fio_malloc(0), 16) failed!\n");
|
8695
|
+
fio_free(rm0);
|
8672
8696
|
}
|
8673
8697
|
{
|
8698
|
+
size_t pool_size = 0;
|
8699
|
+
FIO_LS_EMBD_FOR(&memory.available, node) { ++pool_size; }
|
8674
8700
|
mem = fio_mmap(512);
|
8675
8701
|
FIO_ASSERT(mem, "fio_mmap allocation failed!\n");
|
8676
8702
|
fio_free(mem);
|
8703
|
+
size_t new_pool_size = 0;
|
8704
|
+
FIO_LS_EMBD_FOR(&memory.available, node) { ++new_pool_size; }
|
8705
|
+
FIO_ASSERT(new_pool_size == pool_size,
|
8706
|
+
"fio_free of fio_mmap went to memory pool!\n");
|
8677
8707
|
}
|
8678
8708
|
|
8679
8709
|
fprintf(stderr, "* passed.\n");
|
@@ -8684,12 +8714,12 @@ void fio_malloc_test(void) {
|
|
8684
8714
|
Testing Core Callback add / remove / ensure
|
8685
8715
|
***************************************************************************** */
|
8686
8716
|
|
8687
|
-
|
8717
|
+
FIO_FUNC void fio_state_callback_test_task(void *pi) {
|
8688
8718
|
((uintptr_t *)pi)[0] += 1;
|
8689
8719
|
}
|
8690
8720
|
|
8691
8721
|
#define FIO_STATE_TEST_COUNT 10
|
8692
|
-
|
8722
|
+
FIO_FUNC void fio_state_callback_order_test_task(void *pi) {
|
8693
8723
|
static uintptr_t start = FIO_STATE_TEST_COUNT;
|
8694
8724
|
--start;
|
8695
8725
|
FIO_ASSERT((uintptr_t)pi == start,
|
@@ -8697,7 +8727,7 @@ static void fio_state_callback_order_test_task(void *pi) {
|
|
8697
8727
|
(size_t)pi);
|
8698
8728
|
}
|
8699
8729
|
|
8700
|
-
|
8730
|
+
FIO_FUNC void fio_state_callback_test(void) {
|
8701
8731
|
fprintf(stderr, "=== Testing facil.io workflow state callback system\n");
|
8702
8732
|
uintptr_t result = 0;
|
8703
8733
|
uintptr_t other = 0;
|
@@ -8730,9 +8760,9 @@ static void fio_state_callback_test(void) {
|
|
8730
8760
|
Testing fio_timers
|
8731
8761
|
***************************************************************************** */
|
8732
8762
|
|
8733
|
-
|
8763
|
+
FIO_FUNC void fio_timer_test_task(void *arg) { ++(((size_t *)arg)[0]); }
|
8734
8764
|
|
8735
|
-
|
8765
|
+
FIO_FUNC void fio_timer_test(void) {
|
8736
8766
|
fprintf(stderr, "=== Testing facil.io timer system\n");
|
8737
8767
|
size_t result = 0;
|
8738
8768
|
const size_t total = 5;
|
@@ -8796,7 +8826,7 @@ static void fio_timer_test(void) {
|
|
8796
8826
|
Testing listening socket
|
8797
8827
|
***************************************************************************** */
|
8798
8828
|
|
8799
|
-
|
8829
|
+
FIO_FUNC void fio_socket_test(void) {
|
8800
8830
|
/* initialize unix socket name */
|
8801
8831
|
fio_str_s sock_name = FIO_STR_INIT;
|
8802
8832
|
#ifdef P_tmpdir
|
@@ -8896,17 +8926,17 @@ static void fio_socket_test(void) {
|
|
8896
8926
|
Testing listening socket
|
8897
8927
|
***************************************************************************** */
|
8898
8928
|
|
8899
|
-
|
8929
|
+
FIO_FUNC void fio_cycle_test_task(void *arg) {
|
8900
8930
|
fio_stop();
|
8901
8931
|
(void)arg;
|
8902
8932
|
}
|
8903
|
-
|
8933
|
+
FIO_FUNC void fio_cycle_test_task2(void *arg) {
|
8904
8934
|
fprintf(stderr, "* facil.io cycling test fatal error!\n");
|
8905
8935
|
exit(-1);
|
8906
8936
|
(void)arg;
|
8907
8937
|
}
|
8908
8938
|
|
8909
|
-
|
8939
|
+
FIO_FUNC void fio_cycle_test(void) {
|
8910
8940
|
fprintf(stderr,
|
8911
8941
|
"=== Testing facil.io cycling logic (partial - only tests timers)\n");
|
8912
8942
|
fio_mark_time();
|
@@ -8931,18 +8961,18 @@ Testing fio_defer task system
|
|
8931
8961
|
#define FIO_DEFER_TEST_PRINT 0
|
8932
8962
|
#endif
|
8933
8963
|
|
8934
|
-
|
8964
|
+
FIO_FUNC void sample_task(void *i_count, void *unused2) {
|
8935
8965
|
(void)(unused2);
|
8936
8966
|
fio_atomic_add((uintptr_t *)i_count, 1);
|
8937
8967
|
}
|
8938
8968
|
|
8939
|
-
|
8969
|
+
FIO_FUNC void sched_sample_task(void *count, void *i_count) {
|
8940
8970
|
for (size_t i = 0; i < (uintptr_t)count; i++) {
|
8941
8971
|
fio_defer(sample_task, i_count, NULL);
|
8942
8972
|
}
|
8943
8973
|
}
|
8944
8974
|
|
8945
|
-
|
8975
|
+
FIO_FUNC void fio_defer_test(void) {
|
8946
8976
|
const size_t cpu_cores = fio_detect_cpu_cores();
|
8947
8977
|
FIO_ASSERT(cpu_cores, "couldn't detect CPU cores!");
|
8948
8978
|
uintptr_t i_count;
|
@@ -9015,8 +9045,8 @@ typedef struct {
|
|
9015
9045
|
#define FIO_ARY_TYPE uintptr_t
|
9016
9046
|
#include "fio.h"
|
9017
9047
|
|
9018
|
-
|
9019
|
-
|
9048
|
+
FIO_FUNC intptr_t ary_alloc_counter = 0;
|
9049
|
+
FIO_FUNC void copy_s(fio_ary_test_type_s *d, fio_ary_test_type_s *s) {
|
9020
9050
|
++ary_alloc_counter;
|
9021
9051
|
*d = *s;
|
9022
9052
|
}
|
@@ -9028,7 +9058,7 @@ static void copy_s(fio_ary_test_type_s *d, fio_ary_test_type_s *s) {
|
|
9028
9058
|
#define FIO_ARY_DESTROY(obj) (--ary_alloc_counter)
|
9029
9059
|
#include "fio.h"
|
9030
9060
|
|
9031
|
-
void fio_ary_test(void) {
|
9061
|
+
FIO_FUNC void fio_ary_test(void) {
|
9032
9062
|
/* code */
|
9033
9063
|
fio_i_ary__test();
|
9034
9064
|
fio_s_ary__test();
|
@@ -9233,7 +9263,7 @@ FIO_FUNC void fio_set_test(void) {
|
|
9233
9263
|
SipHash tests
|
9234
9264
|
***************************************************************************** */
|
9235
9265
|
|
9236
|
-
|
9266
|
+
FIO_FUNC void fio_siphash_speed_test(void) {
|
9237
9267
|
/* test based on code from BearSSL with credit to Thomas Pornin */
|
9238
9268
|
uint8_t buffer[8192];
|
9239
9269
|
memset(buffer, 'T', sizeof(buffer));
|
@@ -9283,7 +9313,7 @@ static void fio_siphash_speed_test(void) {
|
|
9283
9313
|
}
|
9284
9314
|
}
|
9285
9315
|
|
9286
|
-
void fio_siphash_test(void) {
|
9316
|
+
FIO_FUNC void fio_siphash_test(void) {
|
9287
9317
|
fprintf(stderr, "===================================\n");
|
9288
9318
|
#if NODEBUG
|
9289
9319
|
fio_siphash_speed_test();
|
@@ -9297,7 +9327,7 @@ void fio_siphash_test(void) {
|
|
9297
9327
|
SHA-1 tests
|
9298
9328
|
***************************************************************************** */
|
9299
9329
|
|
9300
|
-
|
9330
|
+
FIO_FUNC void fio_sha1_speed_test(void) {
|
9301
9331
|
/* test based on code from BearSSL with credit to Thomas Pornin */
|
9302
9332
|
uint8_t buffer[8192];
|
9303
9333
|
uint8_t result[21];
|
@@ -9331,7 +9361,7 @@ static void fio_sha1_speed_test(void) {
|
|
9331
9361
|
}
|
9332
9362
|
|
9333
9363
|
#ifdef HAVE_OPENSSL
|
9334
|
-
|
9364
|
+
FIO_FUNC void fio_sha1_open_ssl_speed_test(void) {
|
9335
9365
|
/* test based on code from BearSSL with credit to Thomas Pornin */
|
9336
9366
|
uint8_t buffer[8192];
|
9337
9367
|
uint8_t result[21];
|
@@ -9365,7 +9395,7 @@ static void fio_sha1_open_ssl_speed_test(void) {
|
|
9365
9395
|
}
|
9366
9396
|
#endif
|
9367
9397
|
|
9368
|
-
void fio_sha1_test(void) {
|
9398
|
+
FIO_FUNC void fio_sha1_test(void) {
|
9369
9399
|
// clang-format off
|
9370
9400
|
struct {
|
9371
9401
|
char *str;
|
@@ -9436,12 +9466,13 @@ void fio_sha1_test(void) {
|
|
9436
9466
|
SHA-2 tests
|
9437
9467
|
***************************************************************************** */
|
9438
9468
|
|
9439
|
-
|
9469
|
+
FIO_FUNC char *sha2_variant_names[] = {
|
9440
9470
|
"unknown", "SHA_512", "SHA_256", "SHA_512_256",
|
9441
9471
|
"SHA_224", "SHA_512_224", "none", "SHA_384",
|
9442
9472
|
};
|
9443
9473
|
|
9444
|
-
|
9474
|
+
FIO_FUNC void fio_sha2_speed_test(fio_sha2_variant_e var,
|
9475
|
+
const char *var_name) {
|
9445
9476
|
/* test based on code from BearSSL with credit to Thomas Pornin */
|
9446
9477
|
uint8_t buffer[8192];
|
9447
9478
|
uint8_t result[65];
|
@@ -9474,9 +9505,9 @@ static void fio_sha2_speed_test(fio_sha2_variant_e var, const char *var_name) {
|
|
9474
9505
|
}
|
9475
9506
|
}
|
9476
9507
|
|
9477
|
-
|
9478
|
-
|
9479
|
-
|
9508
|
+
FIO_FUNC void fio_sha2_openssl_speed_test(const char *var_name, int (*init)(),
|
9509
|
+
int (*update)(), int (*final)(),
|
9510
|
+
void *sha) {
|
9480
9511
|
/* test adapted from BearSSL code with credit to Thomas Pornin */
|
9481
9512
|
uint8_t buffer[8192];
|
9482
9513
|
uint8_t result[1024];
|
@@ -9507,7 +9538,7 @@ static void fio_sha2_openssl_speed_test(const char *var_name, int (*init)(),
|
|
9507
9538
|
cycles <<= 1;
|
9508
9539
|
}
|
9509
9540
|
}
|
9510
|
-
void fio_sha2_test(void) {
|
9541
|
+
FIO_FUNC void fio_sha2_test(void) {
|
9511
9542
|
fio_sha2_s s;
|
9512
9543
|
char *expect;
|
9513
9544
|
char *got;
|
@@ -9651,7 +9682,7 @@ error:
|
|
9651
9682
|
Base64 tests
|
9652
9683
|
***************************************************************************** */
|
9653
9684
|
|
9654
|
-
|
9685
|
+
FIO_FUNC void fio_base64_speed_test(void) {
|
9655
9686
|
/* test based on code from BearSSL with credit to Thomas Pornin */
|
9656
9687
|
char buffer[8192];
|
9657
9688
|
char result[8192 * 2];
|
@@ -9706,7 +9737,7 @@ static void fio_base64_speed_test(void) {
|
|
9706
9737
|
}
|
9707
9738
|
}
|
9708
9739
|
|
9709
|
-
void fio_base64_test(void) {
|
9740
|
+
FIO_FUNC void fio_base64_test(void) {
|
9710
9741
|
struct {
|
9711
9742
|
char *str;
|
9712
9743
|
char *base64;
|
@@ -9780,7 +9811,7 @@ void fio_base64_test(void) {
|
|
9780
9811
|
Random Testing
|
9781
9812
|
***************************************************************************** */
|
9782
9813
|
|
9783
|
-
void fio_test_random(void) {
|
9814
|
+
FIO_FUNC void fio_test_random(void) {
|
9784
9815
|
fprintf(stderr, "=== Testing random generator\n");
|
9785
9816
|
uint64_t rnd = fio_rand64();
|
9786
9817
|
FIO_ASSERT((rnd != fio_rand64() && rnd != fio_rand64()),
|
@@ -9818,7 +9849,7 @@ void fio_test_random(void) {
|
|
9818
9849
|
Poll (not kqueue or epoll) tests
|
9819
9850
|
***************************************************************************** */
|
9820
9851
|
#if FIO_ENGINE_POLL
|
9821
|
-
|
9852
|
+
FIO_FUNC void fio_poll_test(void) {
|
9822
9853
|
fprintf(stderr, "=== Testing poll add / remove fd\n");
|
9823
9854
|
fio_poll_add(5);
|
9824
9855
|
FIO_ASSERT(fio_data->start == 5,
|
@@ -9869,11 +9900,11 @@ static void fio_poll_test(void) {
|
|
9869
9900
|
Test UUID Linking
|
9870
9901
|
***************************************************************************** */
|
9871
9902
|
|
9872
|
-
|
9903
|
+
FIO_FUNC void fio_uuid_link_test_on_close(void *obj) {
|
9873
9904
|
fio_atomic_add((uintptr_t *)obj, 1);
|
9874
9905
|
}
|
9875
9906
|
|
9876
|
-
|
9907
|
+
FIO_FUNC void fio_uuid_link_test(void) {
|
9877
9908
|
fprintf(stderr, "=== Testing fio_uuid_link\n");
|
9878
9909
|
uintptr_t called = 0;
|
9879
9910
|
uintptr_t removed = 0;
|
@@ -9896,7 +9927,7 @@ static void fio_uuid_link_test(void) {
|
|
9896
9927
|
Byte Order Testing
|
9897
9928
|
***************************************************************************** */
|
9898
9929
|
|
9899
|
-
|
9930
|
+
FIO_FUNC void fio_str2u_test(void) {
|
9900
9931
|
fprintf(stderr, "=== Testing fio_u2strX and fio_u2strX functions.\n");
|
9901
9932
|
char buffer[32];
|
9902
9933
|
for (int64_t i = -1024; i < 1024; ++i) {
|
@@ -9929,15 +9960,15 @@ Pub/Sub partial tests
|
|
9929
9960
|
|
9930
9961
|
#if FIO_PUBSUB_SUPPORT
|
9931
9962
|
|
9932
|
-
|
9963
|
+
FIO_FUNC void fio_pubsub_test_on_message(fio_msg_s *msg) {
|
9933
9964
|
fio_atomic_add((uintptr_t *)msg->udata1, 1);
|
9934
9965
|
}
|
9935
|
-
|
9966
|
+
FIO_FUNC void fio_pubsub_test_on_unsubscribe(void *udata1, void *udata2) {
|
9936
9967
|
fio_atomic_add((uintptr_t *)udata1, 1);
|
9937
9968
|
(void)udata2;
|
9938
9969
|
}
|
9939
9970
|
|
9940
|
-
|
9971
|
+
FIO_FUNC void fio_pubsub_test(void) {
|
9941
9972
|
fprintf(stderr, "=== Testing pub/sub (partial)\n");
|
9942
9973
|
fio_data->active = 1;
|
9943
9974
|
fio_data->is_worker = 1;
|
@@ -9953,10 +9984,11 @@ static void fio_pubsub_test(void) {
|
|
9953
9984
|
fio_u2str32((uint8_t *)buffer, 4);
|
9954
9985
|
FIO_ASSERT(fio_str2u32((uint8_t *)buffer) == 4,
|
9955
9986
|
"fio_u2str32 / fio_str2u32 not reversible (4)!");
|
9956
|
-
|
9987
|
+
subscription_s *s2 =
|
9988
|
+
fio_subscribe(.filter = 1, .udata1 = &counter,
|
9957
9989
|
.on_message = fio_pubsub_test_on_message,
|
9958
9990
|
.on_unsubscribe = fio_pubsub_test_on_unsubscribe);
|
9959
|
-
FIO_ASSERT(
|
9991
|
+
FIO_ASSERT(s2, "fio_subscribe FAILED on filtered subscription.");
|
9960
9992
|
fio_publish(.filter = 1);
|
9961
9993
|
++expect;
|
9962
9994
|
fio_defer_perform();
|
@@ -9965,6 +9997,7 @@ static void fio_pubsub_test(void) {
|
|
9965
9997
|
fio_defer_perform();
|
9966
9998
|
FIO_ASSERT(counter == expect, "publishing to filter 2 arrived at filter 1!");
|
9967
9999
|
fio_unsubscribe(s);
|
10000
|
+
fio_unsubscribe(s2);
|
9968
10001
|
++expect;
|
9969
10002
|
fio_defer_perform();
|
9970
10003
|
FIO_ASSERT(counter == expect, "unsubscribe wasn't called for filter 1!");
|
@@ -9987,6 +10020,7 @@ static void fio_pubsub_test(void) {
|
|
9987
10020
|
fio_data->is_worker = 0;
|
9988
10021
|
fio_data->active = 0;
|
9989
10022
|
fio_data->workers = 0;
|
10023
|
+
fio_defer_perform();
|
9990
10024
|
(void)fio_pubsub_test_on_message;
|
9991
10025
|
(void)fio_pubsub_test_on_unsubscribe;
|
9992
10026
|
fprintf(stderr, "* passed.\n");
|
@@ -10004,7 +10038,7 @@ String 2 Number and Number 2 String (partial) testing
|
|
10004
10038
|
#else
|
10005
10039
|
#define FIO_ATOL_TEST_MAX_CYCLES 4096
|
10006
10040
|
#endif
|
10007
|
-
|
10041
|
+
FIO_FUNC void fio_atol_test(void) {
|
10008
10042
|
fprintf(stderr, "=== Testing fio_ltoa and fio_atol (partial)\n");
|
10009
10043
|
#ifndef NODEBUG
|
10010
10044
|
fprintf(stderr,
|
@@ -10159,7 +10193,7 @@ static void fio_atol_test(void) {
|
|
10159
10193
|
String 2 Float and Float 2 String (partial) testing
|
10160
10194
|
***************************************************************************** */
|
10161
10195
|
|
10162
|
-
|
10196
|
+
FIO_FUNC void fio_atof_test(void) {
|
10163
10197
|
fprintf(stderr, "=== Testing fio_ftoa and fio_ftoa (partial)\n");
|
10164
10198
|
#define TEST_DOUBLE(s, d, must) \
|
10165
10199
|
do { \
|