Skip to content

Commit 60e6c82

Browse files
committed
Add a condition variable for waiting on events, and wait for it to be signalled if min_nr hasn't been reached
1 parent 0a8c063 commit 60e6c82

File tree

3 files changed

+52
-4
lines changed

3 files changed

+52
-4
lines changed

fs/aio.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ struct aioctx *aioctx_new(int events_capacity, pid_t pid) {
4545
memset(aioctx_events, 0, sizeof(struct aioctx_event) * events_capacity);
4646

4747
lock_init(&aioctx->lock);
48+
cond_init(&aioctx->cond);
4849

4950
aioctx->refcount = 1;
5051
aioctx->events_capacity = events_capacity;
@@ -65,6 +66,7 @@ void aioctx_retain(struct aioctx *ctx) {
6566

6667
static void _aioctx_decrement_ref(struct aioctx *ctx) {
6768
if (--ctx->refcount == 0) {
69+
cond_destroy(&ctx->cond);
6870
free(ctx->events);
6971
free(ctx);
7072
} else {
@@ -143,6 +145,7 @@ void aioctx_complete_event(struct aioctx *ctx, unsigned int index, int64_t resul
143145
ctx->events[index].data.as_complete = data;
144146
}
145147

148+
notify_once(&ctx->cond);
146149
unlock(&ctx->lock);
147150
}
148151

@@ -171,6 +174,16 @@ bool aioctx_consume_completed_event(struct aioctx *ctx, uint64_t *user_data, add
171174
return result;
172175
}
173176

177+
int aioctx_wait_for_completion(struct aioctx *ctx, struct timespec *timeout) {
178+
if (ctx == NULL) return _EINVAL;
179+
180+
lock(&ctx->lock);
181+
int err = wait_for(&ctx->cond, &ctx->lock, timeout);
182+
unlock(&ctx->lock);
183+
184+
return err;
185+
}
186+
174187
void aioctx_lock(struct aioctx* ctx) {
175188
if (ctx == NULL) return;
176189

fs/aio.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ struct aioctx_event {
9090
struct aioctx {
9191
atomic_uint refcount;
9292
lock_t lock;
93+
cond_t cond;
9394

9495
// Indicates if this context is owned by a task.
9596
//
@@ -192,6 +193,9 @@ void aioctx_cancel_event(struct aioctx *ctx, unsigned int index);
192193
//
193194
// This accepts two result parameters, whose meaning is determined solely by
194195
// the event opcode.
196+
//
197+
// This also signals any threads waiting on the context that an event has been
198+
// completed.
195199
void aioctx_complete_event(struct aioctx *ctx, unsigned int index, int64_t result0, int64_t result1);
196200

197201
// Consume a completed I/O event.
@@ -205,6 +209,19 @@ void aioctx_complete_event(struct aioctx *ctx, unsigned int index, int64_t resul
205209
// from the queue, and the passed-in parameters should not be used.
206210
bool aioctx_consume_completed_event(struct aioctx *ctx, uint64_t *user_data, addr_t *iocbp, struct aioctx_event_complete *completed_data);
207211

212+
// Wait for an event to complete.
213+
//
214+
// This function blocks the current thread until an event completion is posted
215+
// to the context, or the timeout expires. When new events are completed, this
216+
// function will return 0. If the timeout expired, this function will return
217+
// _ETIMEDOUT. Any other error codes should be sent to client code.
218+
//
219+
// Please note that this function returning with 0 is not a guarantee that
220+
// `aioctx_consume_completed_event` will yield data. This function may
221+
// spuriously return 0 or some other thread may have claimed the event in
222+
// between this function returning and the other function being called.
223+
int aioctx_wait_for_completion(struct aioctx *ctx, struct timespec *timeout);
224+
208225
void aioctx_lock(struct aioctx* ctx);
209226
void aioctx_unlock(struct aioctx* ctx);
210227

kernel/aio.c

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "kernel/task.h"
44
#include "kernel/aio.h"
55
#include "kernel/fs.h"
6+
#include "kernel/time.h"
67
#include "fs/aio.h"
78
#include "fs/fd.h"
89

@@ -60,12 +61,24 @@ dword_t sys_io_destroy(dword_t ctx_id) {
6061
return 0;
6162
}
6263

63-
dword_t sys_io_getevents(dword_t ctx_id, dword_t min_nr, dword_t nr, addr_t events, addr_t timeout) {
64-
STRACE("io_getevents(0x%x, %d, %d, 0x%x, 0x%x)", ctx_id, min_nr, nr, events, timeout);
64+
dword_t sys_io_getevents(dword_t ctx_id, dword_t min_nr, dword_t nr, addr_t events, addr_t timeout_addr) {
65+
STRACE("io_getevents(0x%x, %d, %d, 0x%x, 0x%x)", ctx_id, min_nr, nr, events, timeout_addr);
6566

6667
struct aioctx *ctx = aioctx_table_get_and_retain(current->aioctx, ctx_id);
6768
if (ctx == NULL) return _EINVAL;
6869
if (events == 0) return _EFAULT;
70+
71+
struct timespec_ guest_timeout;
72+
struct timespec host_timeout;
73+
struct timespec *timeout = &host_timeout;
74+
75+
if (timeout_addr != 0) {
76+
if (user_get(timeout_addr, guest_timeout)) return _EFAULT;
77+
host_timeout.tv_sec = guest_timeout.sec;
78+
host_timeout.tv_nsec = guest_timeout.nsec;
79+
} else {
80+
timeout = NULL;
81+
}
6982

7083
dword_t i = 0;
7184
for (i = 0; i < nr; i += 1) {
@@ -74,8 +87,13 @@ dword_t sys_io_getevents(dword_t ctx_id, dword_t min_nr, dword_t nr, addr_t even
7487
struct aioctx_event_complete cdata;
7588

7689
if (!aioctx_consume_completed_event(ctx, &user_data, &iocbp, &cdata)) {
77-
//TODO: Block until min_nr events recieved or timeout exceeded
78-
break;
90+
if (i >= min_nr) break;
91+
92+
int err = aioctx_wait_for_completion(ctx, timeout);
93+
94+
if (err == _ETIMEDOUT) break;
95+
if (err < 0) return err;
96+
continue;
7997
}
8098

8199
uint64_t obj = (uint64_t)iocbp;

0 commit comments

Comments
 (0)