aboutsummaryrefslogtreecommitdiff
path: root/src/core/aio.h
blob: 09923d7f17285358086ad211187ba9b879a90521 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//
// Copyright 2017 Garrett D'Amore <garrett@damore.org>
// Copyright 2017 Capitar IT Group BV <info@capitar.com>
//
// This software is supplied under the terms of the MIT License, a
// copy of which should be located in the distribution where this
// file was obtained (LICENSE.txt).  A copy of the license may also be
// found online at https://opensource.org/licenses/MIT.
//

#ifndef CORE_AIO_H
#define CORE_AIO_H

#include "core/defs.h"
#include "core/list.h"
#include "core/taskq.h"
#include "core/thread.h"

typedef struct nni_aio_ops nni_aio_ops;

// An nni_aio is an async I/O handle.
struct nni_aio {
	int      a_result; // Result code (nng_errno)
	size_t   a_count;  // Bytes transferred (I/O only)
	nni_cb   a_cb;     // User specified callback.
	void *   a_cbarg;  // Callback argument.
	nni_time a_expire;

	// These fields are private to the aio framework.
	nni_mtx       a_lk;
	nni_cv        a_cv;
	unsigned      a_flags;
	int           a_refcnt; // prevent use-after-free
	nni_taskq_ent a_tqe;

	// Read/write operations.
	nni_iov a_iov[4];
	int     a_niov;

	// Message operations.
	nni_msg *a_msg;

	// Connect/accept operations.
	void *a_endpt; // opaque endpoint handle
	void *a_pipe;  // opaque pipe handle

	// Resolver operations.
	nni_sockaddr *a_addrs;
	int           a_naddrs;

	// Provider-use fields.
	void (*a_prov_cancel)(nni_aio *);
	void *        a_prov_data;
	nni_list_node a_prov_node;

	// Expire node.
	nni_list_node a_expire_node;
};

// nni_aio_init initializes an aio object.  The callback is called with
// the supplied argument when the operation is complete.  If NULL is
// supplied for the callback, then nni_aio_wake is used in its place,
// and the aio is used for the argument.
extern int nni_aio_init(nni_aio *, nni_cb, void *);

// nni_aio_fini finalizes the aio, releasing resources (locks)
// associated with it.  The caller is responsible for ensuring that any
// associated I/O is unscheduled or complete.  This is safe to call
// on zero'd memory.
extern void nni_aio_fini(nni_aio *);

// nni_aio_result returns the result code (0 on success, or an NNG errno)
// for the operation.  It is only valid to call this when the operation is
// complete (such as when the callback is executed or after nni_aio_wait
// is performed).
extern int nni_aio_result(nni_aio *);

// nni_aio_count returns the number of bytes of data transferred, if any.
// As with nni_aio_result, it is only defined if the I/O operation has
// completed.
extern size_t nni_aio_count(nni_aio *);

// nni_aio_wake wakes any threads blocked in nni_aio_wait.  This is the
// default callback if no other is supplied.  If a user callback is supplied
// then that code must call this routine to wake any waiters (unless the
// user code is certain that there are no such waiters).
extern void nni_aio_wake(nni_aio *);

// nni_aio_wait blocks the caller until the operation is complete, as indicated
// by nni_aio_wake being called.  (Recall nni_aio_wake is the default
// callback if none is supplied.)  If a user supplied callback is provided,
// and that callback does not call nni_aio_wake, then this routine may
// block the caller indefinitely.
extern void nni_aio_wait(nni_aio *);

// nni_aio_list_init creates a list suitable for use by providers using
// the a_prov_node member of the aio.  These operations are not locked,
// but they do have some extra checks -- remove is idempotent for example,
// and append will perform any necessary remove first.
extern void nni_aio_list_init(nni_list *);
extern void nni_aio_list_append(nni_list *, nni_aio *);
extern void nni_aio_list_remove(nni_aio *);
extern int  nni_aio_list_active(nni_aio *);

// nni_aio_finish is called by the provider when an operation is complete.
// The provider gives the result code (0 for success, an NNG errno otherwise),
// and the amount of data transferred (if any).
extern void nni_aio_finish(nni_aio *, int, size_t);

// nni_aio_cancel is used to cancel an operation.  Any pending I/O or
// timeouts are canceled if possible, and the callback will be returned
// with the indicated result (NNG_ECLOSED or NNG_ECANCELED is recommended.)
extern void nni_aio_cancel(nni_aio *, int rv);

extern int nni_aio_start(nni_aio *, void (*)(nni_aio *), void *);

// nni_aio_stop is used to abort all further operations on the AIO.
// When this is executed, no further operations or callbacks will be
// executed, and if callbacks or I/O is in progress this will block
// until they are either canceled or aborted.  (Question: why not just
// nni_fini?)
// extern void nni_aio_stop(nni_aio *);

extern int  nni_aio_sys_init(void);
extern void nni_aio_sys_fini(void);
#endif // CORE_AIO_H