Skip to content

Commit 43c8e44

Browse files
committed
libunit-wasm: Add a luw_mem_splice_file() function
This is inspired by the likes of splice(2) and sendfile(2) in that it takes data from one place and puts it in another. This function write(2)'s the request data straight from the shared memory to a given file (referenced by its file descriptor). This is an alternative to using luw_req_buf_copy() and avoids an extra copying of the request data. E.g /* In the request_handler */ if (total_bytes_wrote == 0) { luw_init_ctx(&ctx, addr, 0); luw_set_req_buf(&ctx, &request_buf, LUW_SRB_NONE); fd = open("/var/tmp/large-file.dat", O_CREAT|O_TRUNC|O_WRONLY, 0666); } total_bytes_wrote += luw_mem_splice_file(addr, fd); if (total_bytes_wrote == luw_get_http_content_len(&ctx)) { close(fd); total_bytes_wrote = 0; luw_http_response_end(); } NOTE: We include a typedef definition for ssize_t in unit-wasm.h, to avoid having a dependency on the wasi-sysroot when generating the rust bindings. ssize_t is defined in sys/types.h which is provided by libc and not the compiler. Signed-off-by: Andrew Clayton <[email protected]>
1 parent 1dd1b34 commit 43c8e44

File tree

2 files changed

+39
-0
lines changed

2 files changed

+39
-0
lines changed

src/c/include/unit/unit-wasm.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,15 @@ typedef enum {
8484
LUW_HTTP_GATEWAY_TIMEOUT = 504,
8585
} luw_http_status_t;
8686

87+
#if !defined(__DEFINED_ssize_t)
88+
/*
89+
* Match the typedef from wasm32-wasi/include/bits/alltypes.h
90+
* without requiring the wasi-sysroot for building the rust
91+
* stuff.
92+
*/
93+
typedef long ssize_t;
94+
#endif
95+
8796
struct luw_hdr_field {
8897
u32 name_off;
8998
u32 name_len;
@@ -239,6 +248,7 @@ extern int luw_mem_writep(luw_ctx_t *ctx, const char *fmt, ...);
239248
extern size_t luw_mem_writep_data(luw_ctx_t *ctx, const u8 *src, size_t size);
240249
extern void luw_req_buf_append(luw_ctx_t *ctx, const u8 *src);
241250
extern void luw_req_buf_copy(luw_ctx_t *ctx, const u8 *src);
251+
extern ssize_t luw_mem_splice_file(const u8 *src, int fd);
242252
extern size_t luw_mem_fill_buf_from_req(luw_ctx_t *ctx, size_t from);
243253
extern void luw_mem_reset(luw_ctx_t *ctx);
244254
extern void luw_http_set_response_status(luw_http_status_t status);

src/c/libunit-wasm.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,16 @@
1414
#include <stdarg.h>
1515
#include <string.h>
1616
#include <strings.h>
17+
#include <unistd.h>
1718
#include <errno.h>
1819

1920
#include "unit/unit-wasm.h"
2021

22+
#define MIN(a, b) \
23+
({ __typeof__(a) _a = (a); \
24+
__typeof__ (b) _b = (b); \
25+
_a < _b ? _a : _b; })
26+
2127
/*
2228
* Some handlers are required some are optional.
2329
*
@@ -315,6 +321,29 @@ void luw_req_buf_copy(luw_ctx_t *ctx, const u8 *src)
315321
ctx->req->total_content_sent = req->total_content_sent;
316322
}
317323

324+
/* Copy data from the request to a given file-descriptor. */
325+
ssize_t luw_mem_splice_file(const u8 *src, int fd)
326+
{
327+
struct luw_req *req = (struct luw_req *)src;
328+
size_t written = 0;
329+
size_t bytes_splice = 1024 * 128; /* It's what cp(1) uses */
330+
331+
do {
332+
ssize_t bytes_wrote;
333+
334+
bytes_splice = MIN(bytes_splice, req->content_sent - written);
335+
336+
bytes_wrote = write(fd, src + req->content_off + written,
337+
bytes_splice);
338+
if (bytes_wrote == -1)
339+
return -1;
340+
341+
written += bytes_wrote;
342+
} while (written < req->content_sent);
343+
344+
return written;
345+
}
346+
318347
/*
319348
* Convenience function to fill the response buffer with data from
320349
* the request buffer.

0 commit comments

Comments
 (0)