aboutsummaryrefslogtreecommitdiff
path: root/src/core/ioev.h
blob: e635e0c0124043573ed96366f8694ee96544b9e9 (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
//
// Copyright 2017 Garrett D'Amore <garrett@damore.org>
//
// 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_IOEV_H
#define CORE_IOEV_H

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

typedef struct nni_ioev_ops	nni_ioev_ops;
typedef struct nni_ioev		nni_ioev;

// Provider specific operations on I/O events.  We only have cancellation
// at present.
struct nni_ioev_ops {
	// Cancel the I/O.  This should not callback up, but instead should
	// just do whatever is necessary to free provider specific state,
	// and unlink the I/O from any schedule.  The I/O itself will not
	// have been started if this is called.
	void (*ip_cancel)(void *);
};

// An nni_iov is an I/O event handle, used to represent asynchronous I/O.
// These take several different forms.
struct nni_ioev {
	int		ie_result;      // Result code (nng_errno)
	size_t		ie_count;       // Bytes transferred (I/O only)
	nni_cb		ie_cb;          // User specified callback.
	void *		ie_cbarg;       // Callback argument.

	// These fields are private to the io events framework.
	nni_mtx		ie_lk;
	nni_cv		ie_cv;
	unsigned	ie_flags;

	// Provider data.
	nni_ioev_ops	ie_prov_ops;
	void *		ie_prov_data;
};

// nni_ioev_init initializes an IO event.  The callback is called with
// the supplied argument when the operation is complete.  If NULL is
// supplied for the callback, then nni_ioev_wake is used in its place,
// and the ioev is used for the argument.
extern void nni_ioev_init(nni_ioev *, nni_cb, void *);

// nni_ioev_fini finalizes the IO event, releasing resources (locks)
// associated with it.  The caller is responsible for ensuring that any
// associated I/O is unscheduled or complete.
extern void nni_ioev_fini(nni_ioev *);

// nni_ioev_cancel cancels the IO event.  The result will be NNG_ECANCELED,
// unless the underlying IO has already completed.
extern void nni_ioev_cancel(nni_ioev *);

// nni_ioev_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_ioev_wait
// is performed).
extern int nni_ioev_result(nni_ioev *);

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

// nni_ioev_wake wakes any threads blocked in nni_ioev_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_ioev_wake(nni_ioev *);

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

// I/O provider related functions.
extern void nni_ioev_set_ops(nni_ioev *, nni_ioev_ops *, void *);

// nni_ioev_busy is called by the provider to begin an operation, marking
// the IO busy.  The framework will avoid calling back into the provider
// (for cancellation for example) while the ioev is busy.  It is important
// that the busy state be held for only brief periods of time, such as while
// a non-blocking I/O operation is in progress.  If the IO is canceled (or
// a cancellation is in progress), the function will return NNG_ECANCELED.
// In this case, the provider must not perform any further I/O operations,
// and must not call the completion routine.  Otherwise zero is returned.
extern int nni_ioev_busy(nni_ioev *);

// nni_ioev_unbusy clears the "busy" state set by nni_ioev_busy.
extern void nni_ioev_unbusy(nni_ioev *);

// nni_ioev_finish is called by the provider when an operation is complete.
// (This can be for any reason other than cancellation.)  The provider gives
// the result code (0 for success, an NNG errno otherwise), and the amount of
// data transferred (if any).  The ioev must have been marked busy when this
// is called.  The ioev busy state is automatically cleared by this routine.
extern void nni_ioev_finish(nni_ioev *, int, size_t);

#endif // CORE_IOEV_H