Add io_create_file, io_open_file
This commit is contained in:
@@ -1,2 +1,3 @@
|
|||||||
example
|
example
|
||||||
example.exe
|
example.exe
|
||||||
|
file_*.txt
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
|
#define NUM_OPS 3
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
struct io_operation ops[100];
|
struct io_operation ops[100];
|
||||||
@@ -8,13 +10,26 @@ int main()
|
|||||||
if (!io_context_init(&ioc, ops, sizeof(ops)/sizeof(ops[0])))
|
if (!io_context_init(&ioc, ops, sizeof(ops)/sizeof(ops[0])))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
io_handle files[NUM_OPS];
|
||||||
|
|
||||||
|
for (int i = 0; i < NUM_OPS; i++) {
|
||||||
|
char name[1<<8];
|
||||||
|
snprintf(name, sizeof(name), "file_%d.txt", i);
|
||||||
|
files[i] = io_create_file(&ioc, name, IO_CREATE_CANTEXIST, NULL);
|
||||||
|
if (files[i] == IO_INVALID_HANDLE)
|
||||||
|
fprintf(stderr, "Couldn't create '%s'\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int started = 0;
|
||||||
char msg[] = "Hello, world!\n";
|
char msg[] = "Hello, world!\n";
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < NUM_OPS; i++) {
|
||||||
if (!io_start_send(&ioc, io_get_stdout(), msg, sizeof(msg), NULL))
|
if (io_start_send(&ioc, files[i], msg, sizeof(msg)-1))
|
||||||
|
started++;
|
||||||
|
else
|
||||||
fprintf(stderr, "ERROR\n");
|
fprintf(stderr, "ERROR\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < started; i++) {
|
||||||
struct io_event ev;
|
struct io_event ev;
|
||||||
io_wait(&ioc, &ev);
|
io_wait(&ioc, &ev);
|
||||||
fprintf(stderr, "CONCLUDED\n");
|
fprintf(stderr, "CONCLUDED\n");
|
||||||
|
|||||||
@@ -9,14 +9,51 @@
|
|||||||
* Declare Windows symbols locally to avoid including windows.h
|
* Declare Windows symbols locally to avoid including windows.h
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define GENERIC_READ 0x80000000ULL
|
||||||
|
#define GENERIC_WRITE 0x40000000ULL
|
||||||
|
|
||||||
|
#define CREATE_NEW 1
|
||||||
|
#define CREATE_ALWAYS 2
|
||||||
|
#define OPEN_EXISTING 3
|
||||||
|
#define OPEN_ALWAYS 4
|
||||||
|
|
||||||
|
#define FILE_ATTRIBUTE_NORMAL 0x00000080ULL
|
||||||
|
#define FILE_FLAG_OVERLAPPED 0x40000000ULL
|
||||||
|
|
||||||
#define ERROR_IO_PENDING 997l
|
#define ERROR_IO_PENDING 997l
|
||||||
|
|
||||||
extern int ReadFile(void *handle, void *dst, unsigned long max, unsigned long *num, struct io_overlap *ov);
|
struct security_attr {
|
||||||
extern int WriteFile(void *handle, const void *src, unsigned long max, unsigned long *num, struct io_overlap *ov);
|
unsigned long size;
|
||||||
extern void *CreateIoCompletionPort(void *handle, void *existing_ioport, unsigned long *ptr, unsigned long num_threads);
|
void *desc;
|
||||||
extern int CloseHandle(void *handle);
|
int inherit_handle;
|
||||||
extern unsigned long GetLastError();
|
};
|
||||||
extern int GetQueuedCompletionStatus(void *ioport, unsigned long *num, unsigned long *key, struct io_overlap **ov, unsigned long timeout);
|
|
||||||
|
extern void*
|
||||||
|
CreateFileA(const char *name, unsigned long access,
|
||||||
|
unsigned long share, struct security_attr *sec,
|
||||||
|
unsigned long creation, unsigned long flags,
|
||||||
|
void *template);
|
||||||
|
|
||||||
|
extern int
|
||||||
|
ReadFile(void *handle, void *dst, unsigned long max,
|
||||||
|
unsigned long *num, struct io_overlap *ov);
|
||||||
|
|
||||||
|
extern int
|
||||||
|
WriteFile(void *handle, const void *src, unsigned long max,
|
||||||
|
unsigned long *num, struct io_overlap *ov);
|
||||||
|
|
||||||
|
extern void*
|
||||||
|
CreateIoCompletionPort(void *handle, void *existing_ioport,
|
||||||
|
unsigned long *ptr, unsigned long num_threads);
|
||||||
|
|
||||||
|
extern int
|
||||||
|
CloseHandle(void *handle);
|
||||||
|
|
||||||
|
extern unsigned long
|
||||||
|
GetLastError();
|
||||||
|
|
||||||
|
extern int
|
||||||
|
GetQueuedCompletionStatus(void *ioport, unsigned long *num, unsigned long *key, struct io_overlap **ov, unsigned long timeout);
|
||||||
|
|
||||||
bool io_context_init(struct io_context *ioc,
|
bool io_context_init(struct io_context *ioc,
|
||||||
struct io_operation *ops,
|
struct io_operation *ops,
|
||||||
@@ -26,6 +63,9 @@ bool io_context_init(struct io_context *ioc,
|
|||||||
if (handle == IO_INVALID_HANDLE)
|
if (handle == IO_INVALID_HANDLE)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < max_ops; i++)
|
||||||
|
ops[i].type = IO_VOID;
|
||||||
|
|
||||||
ioc->handle = handle;
|
ioc->handle = handle;
|
||||||
ioc->max_ops = max_ops;
|
ioc->max_ops = max_ops;
|
||||||
ioc->ops = ops;
|
ioc->ops = ops;
|
||||||
@@ -46,8 +86,11 @@ static struct io_operation *alloc_op(struct io_context *ioc)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool io_start_recv(struct io_context *ioc, io_handle handle,
|
bool io_start_recv(struct io_context *ioc, io_handle handle,
|
||||||
void *dst, uint32_t max, void *user)
|
void *dst, uint32_t max)
|
||||||
{
|
{
|
||||||
|
if (handle == IO_INVALID_HANDLE)
|
||||||
|
return false;
|
||||||
|
|
||||||
struct io_operation *op = alloc_op(ioc);
|
struct io_operation *op = alloc_op(ioc);
|
||||||
if (op == NULL)
|
if (op == NULL)
|
||||||
return false;
|
return false;
|
||||||
@@ -58,14 +101,16 @@ bool io_start_recv(struct io_context *ioc, io_handle handle,
|
|||||||
if (!ok && GetLastError() != ERROR_IO_PENDING)
|
if (!ok && GetLastError() != ERROR_IO_PENDING)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
op->user = user;
|
|
||||||
op->type = IO_RECV;
|
op->type = IO_RECV;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool io_start_send(struct io_context *ioc, io_handle handle,
|
bool io_start_send(struct io_context *ioc, io_handle handle,
|
||||||
void *src, uint32_t num, void *user)
|
void *src, uint32_t num)
|
||||||
{
|
{
|
||||||
|
if (handle == IO_INVALID_HANDLE)
|
||||||
|
return false;
|
||||||
|
|
||||||
struct io_operation *op = alloc_op(ioc);
|
struct io_operation *op = alloc_op(ioc);
|
||||||
if (op == NULL)
|
if (op == NULL)
|
||||||
return false;
|
return false;
|
||||||
@@ -76,20 +121,133 @@ bool io_start_send(struct io_context *ioc, io_handle handle,
|
|||||||
if (!ok && GetLastError() != ERROR_IO_PENDING)
|
if (!ok && GetLastError() != ERROR_IO_PENDING)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
op->user = user;
|
|
||||||
op->type = IO_SEND;
|
op->type = IO_SEND;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool io_start_accept(struct io_context *ioc, io_handle handle, void *user)
|
bool io_start_accept(struct io_context *ioc, io_handle handle)
|
||||||
{
|
{
|
||||||
|
if (handle == IO_INVALID_HANDLE)
|
||||||
|
return false;
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned long
|
||||||
|
convert_timeout(int timeout)
|
||||||
|
{
|
||||||
|
if (timeout < 0)
|
||||||
|
return ~0U;
|
||||||
|
else
|
||||||
|
return timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct io_operation *op_from_ov(struct io_overlap *ov)
|
||||||
|
{
|
||||||
|
return (struct io_operation*) ((char*) ov - offsetof(struct io_operation, ov));
|
||||||
|
}
|
||||||
|
|
||||||
void io_wait(struct io_context *ioc, struct io_event *ev)
|
void io_wait(struct io_context *ioc, struct io_event *ev)
|
||||||
{
|
{
|
||||||
// TODO
|
void *user;
|
||||||
|
struct io_overlap *ov;
|
||||||
|
unsigned long num;
|
||||||
|
int ok = GetQueuedCompletionStatus(ioc->handle, &num, (unsigned long*) &user, &ov, convert_timeout(-1));
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
|
||||||
|
if (ov == NULL) {
|
||||||
|
/*
|
||||||
|
* General failure
|
||||||
|
*/
|
||||||
|
ev->error = true;
|
||||||
|
ev->user = NULL; // The user must discriminate between general errors and specific operation errors through the user pointer. Not ideal
|
||||||
|
ev->type = IO_VOID;
|
||||||
|
} else {
|
||||||
|
/*
|
||||||
|
* Operation failure
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct io_operation *op = op_from_ov(ov);
|
||||||
|
|
||||||
|
ev->error = true;
|
||||||
|
ev->user = user;
|
||||||
|
ev->type = op->type;
|
||||||
|
|
||||||
|
switch (op->type) {
|
||||||
|
default:break;
|
||||||
|
case IO_RECV: ev->num = 0; break;
|
||||||
|
case IO_SEND: ev->num = 0; break;
|
||||||
|
case IO_ACCEPT: ev->handle = IO_INVALID_HANDLE; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
op->type = IO_VOID; // Mark unused
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct io_operation *op = op_from_ov(ov);
|
||||||
|
|
||||||
|
ev->error = false;
|
||||||
|
ev->user = user;
|
||||||
|
ev->type = op->type;
|
||||||
|
|
||||||
|
switch (op->type) {
|
||||||
|
default:break;
|
||||||
|
case IO_RECV: ev->num = num; break;
|
||||||
|
case IO_SEND: ev->num = num; break;
|
||||||
|
case IO_ACCEPT: /* TODO */ break;
|
||||||
|
}
|
||||||
|
|
||||||
|
op->type = IO_VOID; // Mark unused
|
||||||
|
}
|
||||||
|
|
||||||
|
io_handle io_open_file(struct io_context *ioc,
|
||||||
|
const char *name,
|
||||||
|
int flags, void *user)
|
||||||
|
{
|
||||||
|
unsigned long access = 0;
|
||||||
|
if (flags & IO_ACCESS_RD) access |= GENERIC_READ;
|
||||||
|
if (flags & IO_ACCESS_WR) access |= GENERIC_WRITE;
|
||||||
|
|
||||||
|
io_handle handle = CreateFileA(name, access, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
||||||
|
if (handle == IO_INVALID_HANDLE)
|
||||||
|
return IO_INVALID_HANDLE;
|
||||||
|
|
||||||
|
if (CreateIoCompletionPort(handle, ioc->handle, user, 0) == NULL) {
|
||||||
|
CloseHandle(handle);
|
||||||
|
return IO_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
io_handle io_create_file(struct io_context *ioc,
|
||||||
|
const char *name,
|
||||||
|
int flags, void *user)
|
||||||
|
{
|
||||||
|
unsigned long flags2 = 0;
|
||||||
|
|
||||||
|
if (flags & IO_CREATE_CANTEXIST)
|
||||||
|
flags2 = CREATE_NEW;
|
||||||
|
else {
|
||||||
|
if (flags & IO_CREATE_OVERWRITE)
|
||||||
|
flags2 = CREATE_ALWAYS;
|
||||||
|
else
|
||||||
|
flags2 = OPEN_ALWAYS;
|
||||||
|
}
|
||||||
|
|
||||||
|
io_handle handle = CreateFileA(name, GENERIC_WRITE, 0, NULL, flags2, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
||||||
|
if (handle == IO_INVALID_HANDLE)
|
||||||
|
return IO_INVALID_HANDLE;
|
||||||
|
|
||||||
|
if (CreateIoCompletionPort(handle, ioc->handle, user, 0) == NULL) {
|
||||||
|
CloseHandle(handle);
|
||||||
|
return IO_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
@@ -97,6 +255,8 @@ void io_wait(struct io_context *ioc, struct io_event *ev)
|
|||||||
|
|
||||||
#if IO_PLATFORM_LINUX
|
#if IO_PLATFORM_LINUX
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
@@ -124,8 +284,10 @@ bool io_context_init(struct io_context *ioc,
|
|||||||
ioc->ops = ops;
|
ioc->ops = ops;
|
||||||
ioc->max_ops = max_ops;
|
ioc->max_ops = max_ops;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < max_ops; i++)
|
for (uint32_t i = 0; i < max_ops; i++) {
|
||||||
ioc->ops[i].type = IO_VOID;
|
ioc->ops[i].type = IO_VOID;
|
||||||
|
ioc->ops[i].handle = IO_INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
struct io_uring_params p;
|
struct io_uring_params p;
|
||||||
void *sq_ptr, *cq_ptr;
|
void *sq_ptr, *cq_ptr;
|
||||||
@@ -228,21 +390,57 @@ static bool start_oper(struct io_context *ioc,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct io_operation *alloc_op(struct io_context *ioc)
|
static struct io_operation *alloc_op(struct io_context *ioc,
|
||||||
|
io_handle handle, void **user)
|
||||||
{
|
{
|
||||||
for (uint32_t i = 0; i < ioc->max_ops; i++)
|
assert(handle != IO_INVALID_HANDLE);
|
||||||
if (ioc->ops[i].type == IO_VOID)
|
|
||||||
return &ioc->ops[i];
|
/*
|
||||||
return NULL;
|
* Look for an empty struct and the struct associated to
|
||||||
|
* this handle.
|
||||||
|
*/
|
||||||
|
struct io_operation *ref = NULL;
|
||||||
|
struct io_operation *empty = NULL;
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < ioc->max_ops; i++) {
|
||||||
|
|
||||||
|
struct io_operation *op = &ioc->ops[i];
|
||||||
|
|
||||||
|
if (op->handle == handle) {
|
||||||
|
ref = op;
|
||||||
|
if (empty) break;
|
||||||
|
} else {
|
||||||
|
if (op->type == IO_VOID && op->handle == IO_INVALID_HANDLE) {
|
||||||
|
empty = op;
|
||||||
|
if (ref) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(ref && empty);
|
||||||
|
|
||||||
|
*user = ref->user;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If the reference slot is unused, use that one,
|
||||||
|
* else use the first empty one.
|
||||||
|
*/
|
||||||
|
if (ref->type == IO_VOID)
|
||||||
|
return ref;
|
||||||
|
else
|
||||||
|
return empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool io_start_recv(struct io_context *ioc, io_handle handle,
|
bool io_start_recv(struct io_context *ioc, io_handle handle,
|
||||||
void *dst, uint32_t max, void *user)
|
void *dst, uint32_t max)
|
||||||
{
|
{
|
||||||
|
if (handle == IO_INVALID_HANDLE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
void *user;
|
||||||
struct io_operation *op;
|
struct io_operation *op;
|
||||||
struct io_uring_sqe sqe;
|
struct io_uring_sqe sqe;
|
||||||
|
|
||||||
op = alloc_op(ioc);
|
op = alloc_op(ioc, handle, &user);
|
||||||
if (op == NULL)
|
if (op == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -262,12 +460,16 @@ bool io_start_recv(struct io_context *ioc, io_handle handle,
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool io_start_send(struct io_context *ioc, io_handle handle,
|
bool io_start_send(struct io_context *ioc, io_handle handle,
|
||||||
void *src, uint32_t num, void *user)
|
void *src, uint32_t num)
|
||||||
{
|
{
|
||||||
|
if (handle == IO_INVALID_HANDLE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
void *user;
|
||||||
struct io_operation *op;
|
struct io_operation *op;
|
||||||
struct io_uring_sqe sqe;
|
struct io_uring_sqe sqe;
|
||||||
|
|
||||||
op = alloc_op(ioc);
|
op = alloc_op(ioc, handle, &user);
|
||||||
if (op == NULL)
|
if (op == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -286,12 +488,16 @@ bool io_start_send(struct io_context *ioc, io_handle handle,
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool io_start_accept(struct io_context *ioc, io_handle handle, void *user)
|
bool io_start_accept(struct io_context *ioc, io_handle handle)
|
||||||
{
|
{
|
||||||
|
if (handle == IO_INVALID_HANDLE)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
void *user;
|
||||||
struct io_operation *op;
|
struct io_operation *op;
|
||||||
struct io_uring_sqe sqe;
|
struct io_uring_sqe sqe;
|
||||||
|
|
||||||
op = alloc_op(ioc);
|
op = alloc_op(ioc, handle, &user);
|
||||||
if (op == NULL)
|
if (op == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -351,4 +557,65 @@ void io_wait(struct io_context *ioc, struct io_event *ev)
|
|||||||
atomic_store(ioc->completions.head, head+1);
|
atomic_store(ioc->completions.head, head+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct io_operation*
|
||||||
|
unassociated_operation_struct(struct io_context *ioc)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < ioc->max_ops; i++) {
|
||||||
|
struct io_operation *op = &ioc->ops[i];
|
||||||
|
if (op->type == IO_VOID && op->handle == IO_INVALID_HANDLE)
|
||||||
|
return op;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
io_handle io_open_file(struct io_context *ioc,
|
||||||
|
const char *name,
|
||||||
|
int flags, void *user)
|
||||||
|
{
|
||||||
|
struct io_operation *op;
|
||||||
|
op = unassociated_operation_struct(ioc);
|
||||||
|
if (op == NULL)
|
||||||
|
return IO_INVALID_HANDLE;
|
||||||
|
|
||||||
|
int flags2 = 0;
|
||||||
|
if (flags & IO_ACCESS_RD) flags2 |= O_RDONLY;
|
||||||
|
if (flags & IO_ACCESS_WR) flags2 |= O_WRONLY;
|
||||||
|
|
||||||
|
io_handle fd = open(name, flags2);
|
||||||
|
if (fd < 0)
|
||||||
|
return IO_INVALID_HANDLE;
|
||||||
|
|
||||||
|
op->handle = fd;
|
||||||
|
op->user = user;
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
io_handle io_create_file(struct io_context *ioc,
|
||||||
|
const char *name,
|
||||||
|
int flags, void *user)
|
||||||
|
{
|
||||||
|
struct io_operation *op;
|
||||||
|
op = unassociated_operation_struct(ioc);
|
||||||
|
if (op == NULL)
|
||||||
|
return IO_INVALID_HANDLE;
|
||||||
|
|
||||||
|
int flags2 = O_CREAT | O_WRONLY;
|
||||||
|
|
||||||
|
if (flags & IO_CREATE_CANTEXIST)
|
||||||
|
flags2 |= O_EXCL;
|
||||||
|
else {
|
||||||
|
if (flags & IO_CREATE_OVERWRITE)
|
||||||
|
flags2 |= O_TRUNC;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: is 0666 ok?
|
||||||
|
int fd = open(name, flags2, 0666);
|
||||||
|
if (fd < 0)
|
||||||
|
return IO_INVALID_HANDLE;
|
||||||
|
|
||||||
|
op->handle = fd;
|
||||||
|
op->user = user;
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -61,9 +61,15 @@ enum io_optype {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct io_operation {
|
struct io_operation {
|
||||||
enum io_optype type; // =IO_VOID when the struct is unused
|
|
||||||
void *user;
|
void *user;
|
||||||
|
|
||||||
|
enum io_optype type;
|
||||||
|
|
||||||
|
#if IO_PLATFORM_LINUX
|
||||||
|
io_handle handle;
|
||||||
|
#endif
|
||||||
|
|
||||||
#if IO_PLATFORM_WINDOWS
|
#if IO_PLATFORM_WINDOWS
|
||||||
struct io_overlap ov;
|
struct io_overlap ov;
|
||||||
#endif
|
#endif
|
||||||
@@ -145,17 +151,16 @@ void io_context_free(struct io_context *ioc);
|
|||||||
* bytes actually written from "dst".
|
* bytes actually written from "dst".
|
||||||
*/
|
*/
|
||||||
bool io_start_recv(struct io_context *ioc, io_handle handle,
|
bool io_start_recv(struct io_context *ioc, io_handle handle,
|
||||||
void *dst, uint32_t max, void *user);
|
void *dst, uint32_t max);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Works like "io_start_recv" but for sending.
|
* Works like "io_start_recv" but for sending.
|
||||||
*/
|
*/
|
||||||
bool io_start_send(struct io_context *ioc, io_handle handle,
|
bool io_start_send(struct io_context *ioc, io_handle handle,
|
||||||
void *src, uint32_t num, void *user);
|
void *src, uint32_t num);
|
||||||
|
|
||||||
|
|
||||||
bool io_start_accept(struct io_context *ioc, io_handle handle,
|
bool io_start_accept(struct io_context *ioc, io_handle handle);
|
||||||
void *user);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wait for the completion of an I/O event.
|
* Wait for the completion of an I/O event.
|
||||||
@@ -163,11 +168,20 @@ bool io_start_accept(struct io_context *ioc, io_handle handle,
|
|||||||
void io_wait(struct io_context *ioc,
|
void io_wait(struct io_context *ioc,
|
||||||
struct io_event *ev);
|
struct io_event *ev);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flags for "io_open_file" and "io_create_file"
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
IO_ACCESS_RD = 1 << 0,
|
||||||
|
IO_ACCESS_WR = 1 << 1,
|
||||||
|
IO_CREATE_OVERWRITE = 1 << 2,
|
||||||
|
IO_CREATE_CANTEXIST = 1 << 3,
|
||||||
|
};
|
||||||
|
|
||||||
io_handle io_open_file(struct io_context *ioc,
|
io_handle io_open_file(struct io_context *ioc,
|
||||||
const char *name, int flags);
|
const char *name, int flags,
|
||||||
|
void *user);
|
||||||
|
|
||||||
io_handle io_create_file(struct io_context *ioc,
|
io_handle io_create_file(struct io_context *ioc,
|
||||||
const char *name, int flags);
|
const char *name, int flags,
|
||||||
|
void *user);
|
||||||
io_handle io_listen(struct io_context *ioc,
|
|
||||||
const char *addr, int port);
|
|
||||||
|
|||||||
Reference in New Issue
Block a user