+#ifdef NDEBUG
+#undef NDEBUG
+#endif
+
+#define _POSIX_C_SOURCE 200809L
+
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/time.h>
+#include <time.h>
#include "meshlink.h"
#include "utils.h"
struct aio_info {
int callbacks;
size_t size;
- struct timeval tv;
+ struct timespec ts;
struct sync_flag flag;
};
struct aio_info aio_infos[2];
};
-static size_t bar_received_len;
-static struct timeval bar_received_tv;
-static struct sync_flag bar_received_flag;
+static size_t b_received_len;
+static struct timespec b_received_ts;
+static struct sync_flag b_received_flag;
static void aio_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *data, size_t len, void *priv) {
(void)mesh;
(void)len;
struct aio_info *info = priv;
- gettimeofday(&info->tv, NULL);
+ clock_gettime(CLOCK_MONOTONIC, &info->ts);
info->callbacks++;
info->size += len;
set_sync_flag(&info->flag, true);
}
-static bool reject_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, uint16_t port, const void *data, size_t len) {
- (void)mesh;
- (void)channel;
- (void)port;
- (void)data;
- (void)len;
-
- return false;
-}
-
static void receive_cb(meshlink_handle_t *mesh, meshlink_channel_t *channel, const void *data, size_t len) {
(void)mesh;
(void)channel;
(void)data;
- bar_received_len += len;
+ b_received_len += len;
- if(bar_received_len >= smallsize) {
- gettimeofday(&bar_received_tv, NULL);
- set_sync_flag(&bar_received_flag, true);
+ if(b_received_len >= smallsize) {
+ clock_gettime(CLOCK_MONOTONIC, &b_received_ts);
+ set_sync_flag(&b_received_flag, true);
}
}
return true;
}
-int main(int argc, char *argv[]) {
- (void)argc;
- (void)argv;
+int main(void) {
+ init_sync_flag(&b_received_flag);
+
+ meshlink_set_log_cb(NULL, MESHLINK_WARNING, log_cb);
// Prepare data buffers
char *outdata = malloc(size);
-
assert(outdata);
for(size_t i = 0; i < size; i++) {
memset(out_infos, 0, sizeof(out_infos));
for(size_t i = 0; i < nchannels; i++) {
+ init_sync_flag(&in_infos[i].aio_infos[0].flag);
+ init_sync_flag(&in_infos[i].aio_infos[1].flag);
+ init_sync_flag(&out_infos[i].aio_infos[0].flag);
+ init_sync_flag(&out_infos[i].aio_infos[1].flag);
+
in_infos[i].data = malloc(size);
assert(in_infos[i].data);
out_infos[i].data = outdata;
// Open two new meshlink instance.
- meshlink_destroy("channels_aio_conf.1");
- meshlink_destroy("channels_aio_conf.2");
-
- meshlink_handle_t *mesh1 = meshlink_open("channels_aio_conf.1", "foo", "channels", DEV_CLASS_BACKBONE);
- assert(mesh1);
-
- meshlink_handle_t *mesh2 = meshlink_open("channels_aio_conf.2", "bar", "channels", DEV_CLASS_BACKBONE);
- assert(mesh2);
-
- mesh2->priv = in_infos;
-
- meshlink_enable_discovery(mesh1, false);
- meshlink_enable_discovery(mesh2, false);
-
- // Import and export both side's data
-
- meshlink_add_address(mesh1, "localhost");
-
- char *data = meshlink_export(mesh1);
- assert(data);
- assert(meshlink_import(mesh2, data));
- free(data);
-
- data = meshlink_export(mesh2);
- assert(data);
- assert(meshlink_import(mesh1, data));
- free(data);
+ meshlink_handle_t *mesh_a, *mesh_b;
+ open_meshlink_pair(&mesh_a, &mesh_b, "channels_aio");
// Set the callbacks.
- meshlink_set_channel_accept_cb(mesh1, reject_cb);
- meshlink_set_channel_accept_cb(mesh2, accept_cb);
+ mesh_b->priv = in_infos;
+
+ meshlink_set_channel_accept_cb(mesh_b, accept_cb);
// Start both instances
- assert(meshlink_start(mesh1));
- assert(meshlink_start(mesh2));
+ start_meshlink_pair(mesh_a, mesh_b);
- // Open channels from foo to bar.
+ // Open channels from a to b.
- meshlink_node_t *bar = meshlink_get_node(mesh1, "bar");
- assert(bar);
+ meshlink_node_t *b = meshlink_get_node(mesh_a, "b");
+ assert(b);
meshlink_channel_t *channels[nchannels + 1];
for(size_t i = 0; i < nchannels + 1; i++) {
- channels[i] = meshlink_channel_open(mesh1, bar, i + 1, NULL, NULL, 0);
+ channels[i] = meshlink_channel_open(mesh_a, b, i + 1, NULL, NULL, 0);
assert(channels[i]);
}
// Send a large buffer of data on each channel.
for(size_t i = 0; i < nchannels; i++) {
- assert(meshlink_channel_aio_send(mesh1, channels[i], outdata, size / 3, aio_cb, &out_infos[i].aio_infos[0]));
- assert(meshlink_channel_aio_send(mesh1, channels[i], outdata + size / 3, size - size / 3, aio_cb, &out_infos[i].aio_infos[1]));
+ assert(meshlink_channel_aio_send(mesh_a, channels[i], outdata, size / 3, aio_cb, &out_infos[i].aio_infos[0]));
+ assert(meshlink_channel_aio_send(mesh_a, channels[i], outdata + size / 3, size - size / 3, aio_cb, &out_infos[i].aio_infos[1]));
}
// Send a little bit on the last channel using a regular send
- assert(meshlink_channel_send(mesh1, channels[nchannels], outdata, smallsize) == smallsize);
+ assert(meshlink_channel_send(mesh_a, channels[nchannels], outdata, smallsize) == (ssize_t)smallsize);
// Wait for everyone to finish.
- assert(wait_sync_flag(&bar_received_flag, 10));
+ assert(wait_sync_flag(&b_received_flag, 10));
for(size_t i = 0; i < nchannels; i++) {
assert(wait_sync_flag(&out_infos[i].aio_infos[0].flag, 10));
// Check that everything is correct.
- assert(bar_received_len == smallsize);
+ assert(b_received_len == smallsize);
for(size_t i = 0; i < nchannels; i++) {
// Data should be transferred intact.
// First batch of data should all be sent and received before the second batch
for(size_t j = 0; j < nchannels; j++) {
- assert(timercmp(&out_infos[i].aio_infos[0].tv, &out_infos[j].aio_infos[1].tv, <=));
- assert(timercmp(&in_infos[i].aio_infos[0].tv, &in_infos[j].aio_infos[1].tv, <=));
+ assert(timespec_lt(&out_infos[i].aio_infos[0].ts, &out_infos[j].aio_infos[1].ts));
+ assert(timespec_lt(&in_infos[i].aio_infos[0].ts, &in_infos[j].aio_infos[1].ts));
}
// The non-AIO transfer should have completed before everything else
- assert(timercmp(&out_infos[i].aio_infos[0].tv, &bar_received_tv, >=));
- assert(timercmp(&in_infos[i].aio_infos[0].tv, &bar_received_tv, >=));
+ assert(!timespec_lt(&out_infos[i].aio_infos[0].ts, &b_received_ts));
+ assert(!timespec_lt(&in_infos[i].aio_infos[0].ts, &b_received_ts));
+
+ free(in_infos[i].data);
}
// Clean up.
- meshlink_close(mesh2);
- meshlink_close(mesh1);
-
- return 0;
+ close_meshlink_pair(mesh_a, mesh_b);
+ free(outdata);
}