VirtualBox

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

Last change on this file since 28688 was 26880, checked in by vboxsync, 15 years ago

gcc warning

  • 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 26880 2010-02-27 09:09:44Z 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 const *pvBuf, size_t cbWrite, void *pvUser)
227{
228 return rtFileAioReqPrepareTransfer(hReq, hFile, LIO_WRITE,
229 off, (void *)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
368 do
369 {
370 int rcBSD = 0;
371 size_t cReqsSubmit = 0;
372 size_t i = 0;
373 PRTFILEAIOREQINTERNAL pReqInt;
374
375 while ( (i < cReqs)
376 && (i < AIO_LISTIO_MAX))
377 {
378 pReqInt = pahReqs[i];
379 if (RTFILEAIOREQ_IS_NOT_VALID(pReqInt))
380 {
381 /* Undo everything and stop submitting. */
382 for (size_t iUndo = 0; iUndo < i; iUndo++)
383 {
384 pReqInt = pahReqs[iUndo];
385 RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED);
386 pReqInt->pCtxInt = NULL;
387 pReqInt->AioCB.aio_sigevent.sigev_notify_kqueue = 0;
388 }
389 rc = VERR_INVALID_HANDLE;
390 break;
391 }
392
393 pReqInt->AioCB.aio_sigevent.sigev_notify_kqueue = pCtxInt->iKQueue;
394 pReqInt->pCtxInt = pCtxInt;
395 RTFILEAIOREQ_SET_STATE(pReqInt, SUBMITTED);
396
397 if (pReqInt->fFlush)
398 break;
399
400 cReqsSubmit++;
401 i++;
402 }
403
404 if (cReqsSubmit)
405 {
406 rcBSD = lio_listio(LIO_NOWAIT, (struct aiocb **)pahReqs, cReqsSubmit, NULL);
407 if (RT_UNLIKELY(rcBSD < 0))
408 {
409 if (rcBSD == EAGAIN)
410 rc = VERR_FILE_AIO_INSUFFICIENT_RESSOURCES;
411 else
412 rc = RTErrConvertFromErrno(errno);
413
414 /* Check which requests got actually submitted and which not. */
415 for (i = 0; i < cReqs; i++)
416 {
417 pReqInt = pahReqs[i];
418 rcBSD = aio_error(&pReqInt->AioCB);
419 if (rcBSD == EINVAL)
420 {
421 /* Was not submitted. */
422 RTFILEAIOREQ_SET_STATE(pReqInt, PREPARED);
423 pReqInt->pCtxInt = NULL;
424 }
425 else if (rcBSD != EINPROGRESS)
426 {
427 /* The request encountered an error. */
428 RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
429 pReqInt->Rc = RTErrConvertFromErrno(rcBSD);
430 pReqInt->pCtxInt = NULL;
431 pReqInt->cbTransfered = 0;
432 }
433 }
434 break;
435 }
436
437 ASMAtomicAddS32(&pCtxInt->cRequests, cReqsSubmit);
438 cReqs -= cReqsSubmit;
439 pahReqs += cReqsSubmit;
440 }
441
442 /* Check if we have a flush request now. */
443 if (cReqs)
444 {
445 pReqInt = pahReqs[0];
446 RTFILEAIOREQ_VALID_RETURN(pReqInt);
447
448 if (pReqInt->fFlush)
449 {
450 /*
451 * lio_listio does not work with flush requests so
452 * we have to use aio_fsync directly.
453 */
454 rcBSD = aio_fsync(O_SYNC, &pReqInt->AioCB);
455 if (RT_UNLIKELY(rcBSD < 0))
456 {
457 RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
458 pReqInt->Rc = RTErrConvertFromErrno(errno);
459 pReqInt->cbTransfered = 0;
460 return pReqInt->Rc;
461 }
462
463 ASMAtomicIncS32(&pCtxInt->cRequests);
464 cReqs--;
465 pahReqs++;
466 }
467 }
468 } while (cReqs);
469
470 return rc;
471}
472
473RTDECL(int) RTFileAioCtxWait(RTFILEAIOCTX hAioCtx, size_t cMinReqs, RTMSINTERVAL cMillies,
474 PRTFILEAIOREQ pahReqs, size_t cReqs, uint32_t *pcReqs)
475{
476 int rc = VINF_SUCCESS;
477 int cRequestsCompleted = 0;
478
479 /*
480 * Validate the parameters, making sure to always set pcReqs.
481 */
482 AssertPtrReturn(pcReqs, VERR_INVALID_POINTER);
483 *pcReqs = 0; /* always set */
484 PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx;
485 RTFILEAIOCTX_VALID_RETURN(pCtxInt);
486 AssertPtrReturn(pahReqs, VERR_INVALID_POINTER);
487 AssertReturn(cReqs != 0, VERR_INVALID_PARAMETER);
488 AssertReturn(cReqs >= cMinReqs, VERR_OUT_OF_RANGE);
489
490 if (RT_UNLIKELY(ASMAtomicReadS32(&pCtxInt->cRequests) == 0))
491 return VERR_FILE_AIO_NO_REQUEST;
492
493 /*
494 * Convert the timeout if specified.
495 */
496 struct timespec *pTimeout = NULL;
497 struct timespec Timeout = {0,0};
498 uint64_t StartNanoTS = 0;
499 if (cMillies != RT_INDEFINITE_WAIT)
500 {
501 Timeout.tv_sec = cMillies / 1000;
502 Timeout.tv_nsec = cMillies % 1000 * 1000000;
503 pTimeout = &Timeout;
504 StartNanoTS = RTTimeNanoTS();
505 }
506
507 /* Wait for at least one. */
508 if (!cMinReqs)
509 cMinReqs = 1;
510
511 /* For the wakeup call. */
512 Assert(pCtxInt->hThreadWait == NIL_RTTHREAD);
513 ASMAtomicWriteHandle(&pCtxInt->hThreadWait, RTThreadSelf());
514
515 while ( cMinReqs
516 && RT_SUCCESS_NP(rc))
517 {
518 struct kevent aKEvents[AIO_MAXIMUM_REQUESTS_PER_CONTEXT];
519 int cRequestsToWait = cMinReqs < AIO_MAXIMUM_REQUESTS_PER_CONTEXT ? cReqs : AIO_MAXIMUM_REQUESTS_PER_CONTEXT;
520 int rcBSD;
521 uint64_t StartTime;
522
523 ASMAtomicXchgBool(&pCtxInt->fWaiting, true);
524 rcBSD = kevent(pCtxInt->iKQueue, NULL, 0, aKEvents, cRequestsToWait, pTimeout);
525 ASMAtomicXchgBool(&pCtxInt->fWaiting, false);
526
527 if (RT_UNLIKELY(rcBSD < 0))
528 {
529 rc = RTErrConvertFromErrno(errno);
530 break;
531 }
532
533 uint32_t const cDone = rcBSD;
534
535 /* Process received events. */
536 for (uint32_t i = 0; i < cDone; i++)
537 {
538 PRTFILEAIOREQINTERNAL pReqInt = (PRTFILEAIOREQINTERNAL)aKEvents[i].udata;
539 AssertPtr(pReqInt);
540 Assert(pReqInt->u32Magic == RTFILEAIOREQ_MAGIC);
541
542 /*
543 * Retrieve the status code here already because the
544 * user may omit the RTFileAioReqGetRC() call and
545 * we will leak kernel ressources then.
546 * This will result in errors during submission
547 * of other requests as soon as the max_aio_queue_per_proc
548 * limit is reached.
549 */
550 int cbTransfered = aio_return(&pReqInt->AioCB);
551
552 if (cbTransfered < 0)
553 {
554 pReqInt->Rc = RTErrConvertFromErrno(cbTransfered);
555 pReqInt->cbTransfered = 0;
556 }
557 else
558 {
559 pReqInt->Rc = VINF_SUCCESS;
560 pReqInt->cbTransfered = cbTransfered;
561 }
562 RTFILEAIOREQ_SET_STATE(pReqInt, COMPLETED);
563 pahReqs[cRequestsCompleted++] = (RTFILEAIOREQ)pReqInt;
564 }
565
566 /*
567 * Done Yet? If not advance and try again.
568 */
569 if (cDone >= cMinReqs)
570 break;
571 cMinReqs -= cDone;
572 cReqs -= cDone;
573
574 if (cMillies != RT_INDEFINITE_WAIT)
575 {
576 /* The API doesn't return ETIMEDOUT, so we have to fix that ourselves. */
577 uint64_t NanoTS = RTTimeNanoTS();
578 uint64_t cMilliesElapsed = (NanoTS - StartNanoTS) / 1000000;
579 if (cMilliesElapsed >= cMillies)
580 {
581 rc = VERR_TIMEOUT;
582 break;
583 }
584
585 /* The syscall supposedly updates it, but we're paranoid. :-) */
586 Timeout.tv_sec = (cMillies - (RTMSINTERVAL)cMilliesElapsed) / 1000;
587 Timeout.tv_nsec = (cMillies - (RTMSINTERVAL)cMilliesElapsed) % 1000 * 1000000;
588 }
589 }
590
591 /*
592 * Update the context state and set the return value.
593 */
594 *pcReqs = cRequestsCompleted;
595 ASMAtomicSubS32(&pCtxInt->cRequests, cRequestsCompleted);
596 Assert(pCtxInt->hThreadWait == RTThreadSelf());
597 ASMAtomicWriteHandle(&pCtxInt->hThreadWait, NIL_RTTHREAD);
598
599 /*
600 * Clear the wakeup flag and set rc.
601 */
602 if ( pCtxInt->fWokenUp
603 && RT_SUCCESS(rc))
604 {
605 ASMAtomicXchgBool(&pCtxInt->fWokenUp, false);
606 rc = VERR_INTERRUPTED;
607 }
608
609 return rc;
610}
611
612RTDECL(int) RTFileAioCtxWakeup(RTFILEAIOCTX hAioCtx)
613{
614 PRTFILEAIOCTXINTERNAL pCtxInt = hAioCtx;
615 RTFILEAIOCTX_VALID_RETURN(pCtxInt);
616
617 /** @todo r=bird: Define the protocol for how to resume work after calling
618 * this function. */
619
620 bool fWokenUp = ASMAtomicXchgBool(&pCtxInt->fWokenUp, true);
621
622 /*
623 * Read the thread handle before the status flag.
624 * If we read the handle after the flag we might
625 * end up with an invalid handle because the thread
626 * waiting in RTFileAioCtxWakeup() might get scheduled
627 * before we read the flag and returns.
628 * We can ensure that the handle is valid if fWaiting is true
629 * when reading the handle before the status flag.
630 */
631 RTTHREAD hThread;
632 ASMAtomicReadHandle(&pCtxInt->hThreadWait, &hThread);
633 bool fWaiting = ASMAtomicReadBool(&pCtxInt->fWaiting);
634 if ( !fWokenUp
635 && fWaiting)
636 {
637 /*
638 * If a thread waits the handle must be valid.
639 * It is possible that the thread returns from
640 * kevent() before the signal is send.
641 * This is no problem because we already set fWokenUp
642 * to true which will let the thread return VERR_INTERRUPTED
643 * and the next call to RTFileAioCtxWait() will not
644 * return VERR_INTERRUPTED because signals are not saved
645 * and will simply vanish if the destination thread can't
646 * receive it.
647 */
648 Assert(hThread != NIL_RTTHREAD);
649 RTThreadPoke(hThread);
650 }
651
652 return VINF_SUCCESS;
653}
654
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