VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/freebsd/fileaio-freebsd.cpp@ 25517

Last change on this file since 25517 was 19562, checked in by vboxsync, 16 years ago

Runtime/Aio: Change API again

  • pcReqs in RTFileAioCtxSubmit is useless because it does not specify which request fails. Removed it again and made it possible to get the state of a request through RTFileAioReqGetRC()
  • Introduce request states for the first point and to catch more errors using the API before a system dependent call is made to return the same error codes one every system for the same cause.
  • Add RTFileAioGetLimits to get global limits and indication for AIO support.
  • General cleanups and fixes
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.3 KB
Line 
1/* $Id: fileaio-freebsd.cpp 19562 2009-05-10 21:44:16Z vboxsync $ */
2/** @file
3 * IPRT - File async I/O, native implementation for the FreeBSD host platform.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#define LOG_GROUP RTLOGGROUP_FILE
36#include <iprt/asm.h>
37#include <iprt/file.h>
38#include <iprt/mem.h>
39#include <iprt/assert.h>
40#include <iprt/string.h>
41#include <iprt/err.h>
42#include <iprt/log.h>
43#include <iprt/thread.h>
44#include "internal/fileaio.h"
45
46#include <sys/types.h>
47#include <sys/event.h>
48#include <sys/time.h>
49#include <sys/sysctl.h>
50#include <aio.h>
51#include <errno.h>
52#include <unistd.h>
53#include <fcntl.h>
54
55/*******************************************************************************
56* Structures and Typedefs *
57*******************************************************************************/
58/**
59 * Async I/O completion context state.
60 */
61typedef struct RTFILEAIOCTXINTERNAL
62{
63 /** Handle to the kernel queue. */
64 int iKQueue;
65 /** Current number of requests active on this context. */
66 volatile int32_t cRequests;
67 /** The ID of the thread which is currently waiting for requests. */
68 volatile RTTHREAD hThreadWait;
69 /** Flag whether the thread was woken up. */
70 volatile bool fWokenUp;
71 /** Flag whether the thread is currently waiting in the syscall. */
72 volatile bool fWaiting;
73 /** Magic value (RTFILEAIOCTX_MAGIC). */
74 uint32_t u32Magic;
75} RTFILEAIOCTXINTERNAL;
76/** Pointer to an internal context structure. */
77typedef RTFILEAIOCTXINTERNAL *PRTFILEAIOCTXINTERNAL;
78
79/**
80 * Async I/O request state.
81 */
82typedef struct RTFILEAIOREQINTERNAL
83{
84 /** The aio control block. Must be the FIRST
85 * element. */
86 struct aiocb AioCB;
87 /** Current state the request is in. */
88 RTFILEAIOREQSTATE enmState;
89 /** Flag whether this is a flush request. */
90 bool fFlush;
91 /** Opaque user data. */
92 void *pvUser;
93 /** Completion context we are assigned to. */
94 PRTFILEAIOCTXINTERNAL pCtxInt;
95 /** Number of bytes actually transfered. */
96 size_t cbTransfered;
97 /** Status code. */
98 int Rc;
99 /** Magic value (RTFILEAIOREQ_MAGIC). */
100 uint32_t u32Magic;
101} RTFILEAIOREQINTERNAL;
102/** Pointer to an internal request structure. */
103typedef RTFILEAIOREQINTERNAL *PRTFILEAIOREQINTERNAL;
104
105
106/*******************************************************************************
107* Defined Constants And Macros *
108*******************************************************************************/
109/** The max number of events to get in one call. */
110#define AIO_MAXIMUM_REQUESTS_PER_CONTEXT 64
111
112RTR3DECL(int) RTFileAioGetLimits(PRTFILEAIOLIMITS pAioLimits)
113{
114 int rcBSD = 0;
115 AssertPtrReturn(pAioLimits, VERR_INVALID_POINTER);
116
117 /*
118 * The AIO API is implemented in a kernel module which is not
119 * loaded by default.
120 * If it is loaded there are additional sysctl parameters.
121 */
122 int cReqsOutstandingMax = 0;
123 size_t cbParameter = sizeof(int);
124
125 rcBSD = sysctlbyname("vfs.aio.max_aio_per_proc", /* name */
126 &cReqsOutstandingMax, /* Where to store the old value. */
127 &cbParameter, /* Size of the memory pointed to. */
128 NULL, /* Where the new value is located. */
129 NULL); /* Where the size of the new value is stored. */
130 if (rcBSD == -1)
131 {
132 /* ENOENT means the value is unknown thus the module is not loaded. */
133 if (errno == ENOENT)
134 return VERR_NOT_SUPPORTED;
135 else
136 return RTErrConvertFromErrno(errno);
137 }
138
139 pAioLimits->cReqsOutstandingMax = cReqsOutstandingMax;
140 pAioLimits->cbBufferAlignment = 0;
141
142 return VINF_SUCCESS;
143}
144
145RTR3DECL(int) RTFileAioReqCreate(PRTFILEAIOREQ phReq)
146{
147 AssertPtrReturn(phReq, VERR_INVALID_POINTER);
148
149 PRTFILEAIOREQINTERNAL pReqInt = (PRTFILEAIOREQINTERNAL)RTMemAllocZ(sizeof(RTFILEAIOREQINTERNAL));
150 if (RT_UNLIKELY(!pReqInt))
151 return VERR_NO_MEMORY;
152
153 /* Ininitialize static parts. */
154 pReqInt->AioCB.aio_sigevent.sigev_notify = SIGEV_KEVENT;
155 pReqInt->AioCB.aio_sigevent.sigev_value.sival_ptr = pReqInt;
156 pReqInt->pCtxInt = NULL;
157 pReqInt->u32Magic = RTFILEAIOREQ_MAGIC;
158 RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
159
160 *phReq = (RTFILEAIOREQ)pReqInt;
161
162 return VINF_SUCCESS;
163}
164
165RTDECL(int) RTFileAioReqDestroy(RTFILEAIOREQ hReq)
166{
167 /*
168 * Validate the handle and ignore nil.
169 */
170 if (hReq == NIL_RTFILEAIOREQ)
171 return VINF_SUCCESS;
172 PRTFILEAIOREQINTERNAL pReqInt = hReq;
173 RTFILEAIOREQ_VALID_RETURN(pReqInt);
174 RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
175
176 /*
177 * Trash the magic and free it.
178 */
179 ASMAtomicUoWriteU32(&pReqInt->u32Magic, ~RTFILEAIOREQ_MAGIC);
180 RTMemFree(pReqInt);
181 return VINF_SUCCESS;
182}
183
184/**
185 * Worker setting up the request.
186 */
187DECLINLINE(int) rtFileAioReqPrepareTransfer(RTFILEAIOREQ hReq, RTFILE hFile,
188 unsigned uTransferDirection,
189 RTFOFF off, void *pvBuf, size_t cbTransfer,
190 void *pvUser)
191{
192 /*
193 * Validate the input.
194 */
195 PRTFILEAIOREQINTERNAL pReqInt = hReq;
196 RTFILEAIOREQ_VALID_RETURN(pReqInt);
197 RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
198 Assert(hFile != NIL_RTFILE);
199 AssertPtr(pvBuf);
200 Assert(off >= 0);
201 Assert(cbTransfer > 0);
202
203 pReqInt->AioCB.aio_sigevent.sigev_notify = SIGEV_KEVENT;
204 pReqInt->AioCB.aio_sigevent.sigev_value.sival_ptr = pReqInt;
205 pReqInt->AioCB.aio_lio_opcode = uTransferDirection;
206 pReqInt->AioCB.aio_fildes = (int)hFile;
207 pReqInt->AioCB.aio_offset = off;
208 pReqInt->AioCB.aio_nbytes = cbTransfer;
209 pReqInt->AioCB.aio_buf = pvBuf;
210 pReqInt->pvUser = pvUser;
211 pReqInt->pCtxInt = NULL;
212 pReqInt->Rc = VERR_FILE_AIO_IN_PROGRESS;
213 RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED);
214
215 return VINF_SUCCESS;
216}
217
218RTDECL(int) RTFileAioReqPrepareRead(RTFILEAIOREQ hReq, RTFILE hFile, RTFOFF off,
219 void *pvBuf, size_t cbRead, void *pvUser)
220{
221 return rtFileAioReqPrepareTransfer(hReq, hFile, LIO_READ,
222 off, pvBuf, cbRead, pvUser);
223}
224
225RTDECL(int) RTFileAioReqPrepareWrite(RTFILEAIOREQ hReq, RTFILE hFile, RTFOFF off,
226 void *pvBuf, size_t cbWrite, void *pvUser)
227{
228 return rtFileAioReqPrepareTransfer(hReq, hFile, LIO_WRITE,
229 off, pvBuf, cbWrite, pvUser);
230}
231
232RTDECL(int) RTFileAioReqPrepareFlush(RTFILEAIOREQ hReq, RTFILE hFile, void *pvUser)
233{
234 PRTFILEAIOREQINTERNAL pReqInt = (PRTFILEAIOREQINTERNAL)hReq;
235
236 RTFILEAIOREQ_VALID_RETURN(pReqInt);
237 Assert(hFile != NIL_RTFILE);
238 RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
239
240 pReqInt->fFlush = true;
241 pReqInt->AioCB.aio_fildes = (int)hFile;
242 pReqInt->pvUser = pvUser;
243 RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED);
244
245 return VINF_SUCCESS;
246}
247
248RTDECL(void *) RTFileAioReqGetUser(RTFILEAIOREQ hReq)
249{
250 PRTFILEAIOREQINTERNAL pReqInt = hReq;
251 RTFILEAIOREQ_VALID_RETURN_RC(pReqInt, NULL);
252
253 return pReqInt->pvUser;
254}
255
256RTDECL(int) RTFileAioReqCancel(RTFILEAIOREQ hReq)
257{
258 PRTFILEAIOREQINTERNAL pReqInt = hReq;
259 RTFILEAIOREQ_VALID_RETURN(pReqInt);
260 RTFILEAIOREQ_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_NOT_SUBMITTED);
261
262
263 int rcBSD = aio_cancel(pReqInt->AioCB.aio_fildes, &pReqInt->AioCB);
264
265 if (rcBSD == AIO_CANCELED)
266 {
267 /*
268 * Decrement request count because the request will never arrive at the
269 * completion port.
270 */
271 AssertMsg(VALID_PTR(pReqInt->pCtxInt),
272 ("Invalid state. Request was canceled but wasn't submitted\n"));
273
274 ASMAtomicDecS32(&pReqInt->pCtxInt->cRequests);
275 pReqInt->Rc = VERR_FILE_AIO_CANCELED;
276 RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
277 return VINF_SUCCESS;
278 }
279 else if (rcBSD == AIO_ALLDONE)
280 return VERR_FILE_AIO_COMPLETED;
281 else if (rcBSD == AIO_NOTCANCELED)
282 return VERR_FILE_AIO_IN_PROGRESS;
283 else
284 return RTErrConvertFromErrno(errno);
285}
286
287RTDECL(int) RTFileAioReqGetRC(RTFILEAIOREQ hReq, size_t *pcbTransfered)
288{
289 PRTFILEAIOREQINTERNAL pReqInt = hReq;
290 RTFILEAIOREQ_VALID_RETURN(pReqInt);
291 AssertPtrNull(pcbTransfered);
292 RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, SUBMITTED, VERR_FILE_AIO_IN_PROGRESS);
293 RTFILEAIOREQ_NOT_STATE_RETURN_RC(pReqInt, PREPARED, VERR_FILE_AIO_NOT_SUBMITTED);
294
295 if ( (RT_SUCCESS(pReqInt->Rc))
296 && (pcbTransfered))
297 *pcbTransfered = pReqInt->cbTransfered;
298
299 return pReqInt->Rc;
300}
301
302RTDECL(int) RTFileAioCtxCreate(PRTFILEAIOCTX phAioCtx, uint32_t cAioReqsMax)
303{
304 int rc = VINF_SUCCESS;
305 PRTFILEAIOCTXINTERNAL pCtxInt;
306 AssertPtrReturn(phAioCtx, VERR_INVALID_POINTER);
307
308 pCtxInt = (PRTFILEAIOCTXINTERNAL)RTMemAllocZ(sizeof(RTFILEAIOCTXINTERNAL));
309 if (RT_UNLIKELY(!pCtxInt))
310 return VERR_NO_MEMORY;
311
312 /* Init the event handle. */
313 pCtxInt->iKQueue = kqueue();
314 if (RT_LIKELY(pCtxInt->iKQueue > 0))
315 {
316 pCtxInt->u32Magic = RTFILEAIOCTX_MAGIC;
317 *phAioCtx = (RTFILEAIOCTX)pCtxInt;
318 }
319 else
320 {
321 RTMemFree(pCtxInt);
322 rc = RTErrConvertFromErrno(errno);
323 }
324
325 return rc;
326}
327
328RTDECL(int) RTFileAioCtxDestroy(RTFILEAIOCTX hAioCtx)
329{
330 /* Validate the handle and ignore nil. */
331 if (hAioCtx == NIL_RTFILEAIOCTX)
332 return VINF_SUCCESS;
333 PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx;
334 RTFILEAIOCTX_VALID_RETURN(pCtxInt);
335
336 /* Cannot destroy a busy context. */
337 if (RT_UNLIKELY(pCtxInt->cRequests))
338 return VERR_FILE_AIO_BUSY;
339
340 close(pCtxInt->iKQueue);
341 ASMAtomicUoWriteU32(&pCtxInt->u32Magic, RTFILEAIOCTX_MAGIC_DEAD);
342 RTMemFree(pCtxInt);
343
344 return VINF_SUCCESS;
345}
346
347RTDECL(uint32_t) RTFileAioCtxGetMaxReqCount(RTFILEAIOCTX hAioCtx)
348{
349 return RTFILEAIO_UNLIMITED_REQS;
350}
351
352RTDECL(int) RTFileAioCtxAssociateWithFile(RTFILEAIOCTX hAioCtx, RTFILE hFile)
353{
354 return VINF_SUCCESS;
355}
356
357RTDECL(int) RTFileAioCtxSubmit(RTFILEAIOCTX hAioCtx, PRTFILEAIOREQ pahReqs, size_t cReqs)
358{
359 /*
360 * Parameter validation.
361 */
362 int rc = VINF_SUCCESS;
363 PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx;
364 RTFILEAIOCTX_VALID_RETURN(pCtxInt);
365 AssertReturn(cReqs > 0, VERR_INVALID_PARAMETER);
366 AssertPtrReturn(pahReqs, VERR_INVALID_POINTER);
367 uint32_t i = cReqs;
368
369 do
370 {
371 int rcBSD = 0;
372 size_t cReqsSubmit = 0;
373 size_t i = 0;
374 PRTFILEAIOREQINTERNAL pReqInt;
375
376 while ( (i < cReqs)
377 && (i < AIO_LISTIO_MAX))
378 {
379 pReqInt = pahReqs[i];
380 if (RTFILEAIOREQ_IS_NOT_VALID(pReqInt))
381 {
382 /* Undo everything and stop submitting. */
383 for (size_t iUndo = 0; iUndo < i; iUndo++)
384 {
385 pReqInt = pahReqs[iUndo];
386 RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED);
387 pReqInt->pCtxInt = NULL;
388 pReqInt->AioCB.aio_sigevent.sigev_notify_kqueue = 0;
389 }
390 rc = VERR_INVALID_HANDLE;
391 break;
392 }
393
394 pReqInt->AioCB.aio_sigevent.sigev_notify_kqueue = pCtxInt->iKQueue;
395 pReqInt->pCtxInt = pCtxInt;
396 RTFILEAIOREQ_SET_STATE(pReqInt, SUBMITTED);
397
398 if (pReqInt->fFlush)
399 break;
400
401 cReqsSubmit++;
402 i++;
403 }
404
405 if (cReqsSubmit)
406 {
407 rcBSD = lio_listio(LIO_NOWAIT, (struct aiocb **)pahReqs, cReqsSubmit, NULL);
408 if (RT_UNLIKELY(rcBSD < 0))
409 {
410 if (rcBSD == EAGAIN)
411 rc = VERR_FILE_AIO_INSUFFICIENT_RESSOURCES;
412 else
413 rc = RTErrConvertFromErrno(errno);
414
415 /* Check which requests got actually submitted and which not. */
416 for (i = 0; i < cReqs; i++)
417 {
418 pReqInt = pahReqs[i];
419 rcBSD = aio_error(&pReqInt->AioCB);
420 if (rcBSD == EINVAL)
421 {
422 /* Was not submitted. */
423 RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED);
424 pReqInt->pCtxInt = NULL;
425 }
426 else if (rcBSD != EINPROGRESS)
427 {
428 /* The request encountered an error. */
429 RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
430 pReqInt->Rc = RTErrConvertFromErrno(rcBSD);
431 pReqInt->pCtxInt = NULL;
432 pReqInt->cbTransfered = 0;
433 }
434 }
435 break;
436 }
437
438 ASMAtomicAddS32(&pCtxInt->cRequests, cReqsSubmit);
439 cReqs -= cReqsSubmit;
440 pahReqs += cReqsSubmit;
441 }
442
443 /* Check if we have a flush request now. */
444 if (cReqs)
445 {
446 pReqInt = pahReqs[0];
447 RTFILEAIOREQ_VALID_RETURN(pReqInt);
448
449 if (pReqInt->fFlush)
450 {
451 /*
452 * lio_listio does not work with flush requests so
453 * we have to use aio_fsync directly.
454 */
455 rcBSD = aio_fsync(O_SYNC, &pReqInt->AioCB);
456 if (RT_UNLIKELY(rcBSD < 0))
457 {
458 RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
459 pReqInt->Rc = RTErrConvertFromErrno(errno);
460 pReqInt->cbTransfered = 0;
461 return pReqInt->Rc;
462 }
463
464 ASMAtomicIncS32(&pCtxInt->cRequests);
465 cReqs--;
466 pahReqs++;
467 }
468 }
469 } while (cReqs);
470
471 return rc;
472}
473
474RTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, unsigned cMillisTimeout,
475 PRTFILEAIOREQ pahReqs, size_t cReqs, uint32_t *pcReqs)
476{
477 int rc = VINF_SUCCESS;
478 int cRequestsCompleted = 0;
479
480 /*
481 * Validate the parameters, making sure to always set pcReqs.
482 */
483 AssertPtrReturn(pcReqs, VERR_INVALID_POINTER);
484 *pcReqs = 0; /* always set */
485 PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx;
486 RTFILEAIOCTX_VALID_RETURN(pCtxInt);
487 AssertPtrReturn(pahReqs, VERR_INVALID_POINTER);
488 AssertReturn(cReqs != 0, VERR_INVALID_PARAMETER);
489 AssertReturn(cReqs >= cMinReqs, VERR_OUT_OF_RANGE);
490
491 if (RT_UNLIKELY(ASMAtomicReadS32(&pCtxInt->cRequests) == 0))
492 return VERR_FILE_AIO_NO_REQUEST;
493
494 /*
495 * Convert the timeout if specified.
496 */
497 struct timespec *pTimeout = NULL;
498 struct timespec Timeout = {0,0};
499 uint64_t StartNanoTS = 0;
500 if (cMillisTimeout != RT_INDEFINITE_WAIT)
501 {
502 Timeout.tv_sec = cMillisTimeout / 1000;
503 Timeout.tv_nsec = cMillisTimeout % 1000 * 1000000;
504 pTimeout = &Timeout;
505 StartNanoTS = RTTimeNanoTS();
506 }
507
508 /* Wait for at least one. */
509 if (!cMinReqs)
510 cMinReqs = 1;
511
512 /* For the wakeup call. */
513 Assert(pCtxInt->hThreadWait == NIL_RTTHREAD);
514 ASMAtomicWriteHandle(&pCtxInt->hThreadWait, RTThreadSelf());
515
516 while ( cMinReqs
517 && RT_SUCCESS_NP(rc))
518 {
519 struct kevent aKEvents[AIO_MAXIMUM_REQUESTS_PER_CONTEXT];
520 int cRequestsToWait = cMinReqs < AIO_MAXIMUM_REQUESTS_PER_CONTEXT ? cReqs : AIO_MAXIMUM_REQUESTS_PER_CONTEXT;
521 int rcBSD;
522 uint64_t StartTime;
523
524 ASMAtomicXchgBool(&pCtxInt->fWaiting, true);
525 rcBSD = kevent(pCtxInt->iKQueue, NULL, 0, aKEvents, cRequestsToWait, pTimeout);
526 ASMAtomicXchgBool(&pCtxInt->fWaiting, false);
527
528 if (RT_UNLIKELY(rcBSD < 0))
529 {
530 rc = RTErrConvertFromErrno(errno);
531 break;
532 }
533
534 uint32_t const cDone = rcBSD;
535
536 /* Process received events. */
537 for (uint32_t i = 0; i < cDone; i++)
538 {
539 PRTFILEAIOREQINTERNAL pReqInt = (PRTFILEAIOREQINTERNAL)aKEvents[i].udata;
540 AssertPtr(pReqInt);
541 Assert(pReqInt->u32Magic == RTFILEAIOREQ_MAGIC);
542
543 /*
544 * Retrieve the status code here already because the
545 * user may omit the RTFileAioReqGetRC() call and
546 * we will leak kernel ressources then.
547 * This will result in errors during submission
548 * of other requests as soon as the max_aio_queue_per_proc
549 * limit is reached.
550 */
551 int cbTransfered = aio_return(&pReqInt->AioCB);
552
553 if (cbTransfered < 0)
554 {
555 pReqInt->Rc = RTErrConvertFromErrno(cbTransfered);
556 pReqInt->cbTransfered = 0;
557 }
558 else
559 {
560 pReqInt->Rc = VINF_SUCCESS;
561 pReqInt->cbTransfered = cbTransfered;
562 }
563 RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
564 pahReqs[cRequestsCompleted++] = (RTFILEAIOREQ)pReqInt;
565 }
566
567 /*
568 * Done Yet? If not advance and try again.
569 */
570 if (cDone >= cMinReqs)
571 break;
572 cMinReqs -= cDone;
573 cReqs -= cDone;
574
575 if (cMillisTimeout != RT_INDEFINITE_WAIT)
576 {
577 /* The API doesn't return ETIMEDOUT, so we have to fix that ourselves. */
578 uint64_t NanoTS = RTTimeNanoTS();
579 uint64_t cMilliesElapsed = (NanoTS - StartNanoTS) / 1000000;
580 if (cMilliesElapsed >= cMillisTimeout)
581 {
582 rc = VERR_TIMEOUT;
583 break;
584 }
585
586 /* The syscall supposedly updates it, but we're paranoid. :-) */
587 Timeout.tv_sec = (cMillisTimeout - (unsigned)cMilliesElapsed) / 1000;
588 Timeout.tv_nsec = (cMillisTimeout - (unsigned)cMilliesElapsed) % 1000 * 1000000;
589 }
590 }
591
592 /*
593 * Update the context state and set the return value.
594 */
595 *pcReqs = cRequestsCompleted;
596 ASMAtomicSubS32(&pCtxInt->cRequests, cRequestsCompleted);
597 Assert(pCtxInt->hThreadWait == RTThreadSelf());
598 ASMAtomicWriteHandle(&pCtxInt->hThreadWait, NIL_RTTHREAD);
599
600 /*
601 * Clear the wakeup flag and set rc.
602 */
603 if ( pCtxInt->fWokenUp
604 && RT_SUCCESS(rc))
605 {
606 ASMAtomicXchgBool(&pCtxInt->fWokenUp, false);
607 rc = VERR_INTERRUPTED;
608 }
609
610 return rc;
611}
612
613RTDECL(int) RTFileAioCtxWakeup(RTFILEAIOCTX hAioCtx)
614{
615 PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx;
616 RTFILEAIOCTX_VALID_RETURN(pCtxInt);
617
618 /** @todo r=bird: Define the protocol for how to resume work after calling
619 * this function. */
620
621 bool fWokenUp = ASMAtomicXchgBool(&pCtxInt->fWokenUp, true);
622
623 /*
624 * Read the thread handle before the status flag.
625 * If we read the handle after the flag we might
626 * end up with an invalid handle because the thread
627 * waiting in RTFileAioCtxWakeup() might get scheduled
628 * before we read the flag and returns.
629 * We can ensure that the handle is valid if fWaiting is true
630 * when reading the handle before the status flag.
631 */
632 RTTHREAD hThread;
633 ASMAtomicReadHandle(&pCtxInt->hThreadWait, &hThread);
634 bool fWaiting = ASMAtomicReadBool(&pCtxInt->fWaiting);
635 if ( !fWokenUp
636 && fWaiting)
637 {
638 /*
639 * If a thread waits the handle must be valid.
640 * It is possible that the thread returns from
641 * kevent() before the signal is send.
642 * This is no problem because we already set fWokenUp
643 * to true which will let the thread return VERR_INTERRUPTED
644 * and the next call to RTFileAioCtxWait() will not
645 * return VERR_INTERRUPTED because signals are not saved
646 * and will simply vanish if the destination thread can't
647 * receive it.
648 */
649 Assert(hThread != NIL_RTTHREAD);
650 RTThreadPoke(hThread);
651 }
652
653 return VINF_SUCCESS;
654}
655
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette