1 /* Copyright (C) 2011 Wildfire Games.
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining
4 * a copy of this software and associated documentation files (the
5 * "Software"), to deal in the Software without restriction, including
6 * without limitation the rights to use, copy, modify, merge, publish,
7 * distribute, sublicense, and/or sell copies of the Software, and to
8 * permit persons to whom the Software is furnished to do so, subject to
9 * the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23 #include "precompiled.h"
24 #include "lib/file/io/io.h"
25
26 #include "lib/sysdep/rtl.h"
27
28 static const StatusDefinition ioStatusDefinitions[] = {
29 { ERR::IO, L"Error during IO", EIO }
30 };
31 STATUS_ADD_DEFINITIONS(ioStatusDefinitions);
32
33 namespace io {
34
35 // this is just a thin wrapper on top of lowio and POSIX aio.
36 // note that the Windows aio implementation requires buffers, sizes and
37 // offsets to be sector-aligned.
38
Issue(aiocb & cb,size_t queueDepth)39 Status Issue(aiocb& cb, size_t queueDepth)
40 {
41 #if CONFIG2_FILE_ENABLE_AIO
42 if(queueDepth > 1)
43 {
44 const int ret = (cb.aio_lio_opcode == LIO_WRITE)? aio_write(&cb): aio_read(&cb);
45 if(ret != 0)
46 WARN_RETURN(StatusFromErrno());
47 }
48 else
49 #else
50 UNUSED2(queueDepth);
51 #endif
52 {
53 ENSURE(lseek(cb.aio_fildes, cb.aio_offset, SEEK_SET) == cb.aio_offset);
54
55 void* buf = (void*)cb.aio_buf; // cast from volatile void*
56 const ssize_t bytesTransferred = (cb.aio_lio_opcode == LIO_WRITE)? write(cb.aio_fildes, buf, cb.aio_nbytes) : read(cb.aio_fildes, buf, cb.aio_nbytes);
57 if(bytesTransferred < 0)
58 WARN_RETURN(StatusFromErrno());
59
60 cb.aio_nbytes = (size_t)bytesTransferred;
61 }
62
63 return INFO::OK;
64 }
65
66
WaitUntilComplete(aiocb & cb,size_t queueDepth)67 Status WaitUntilComplete(aiocb& cb, size_t queueDepth)
68 {
69 #if CONFIG2_FILE_ENABLE_AIO
70 if(queueDepth > 1)
71 {
72 aiocb* const cbs = &cb;
73 timespec* const timeout = 0; // infinite
74 SUSPEND_AGAIN:
75 errno = 0;
76 const int ret = aio_suspend(&cbs, 1, timeout);
77 if(ret != 0)
78 {
79 if(errno == EINTR) // interrupted by signal
80 goto SUSPEND_AGAIN;
81 WARN_RETURN(StatusFromErrno());
82 }
83
84 const int err = aio_error(&cb);
85 ENSURE(err != EINPROGRESS); // else aio_return is undefined
86 ssize_t bytesTransferred = aio_return(&cb);
87 if(bytesTransferred == -1) // transfer failed
88 {
89 errno = err;
90 WARN_RETURN(StatusFromErrno());
91 }
92 cb.aio_nbytes = (size_t)bytesTransferred;
93 }
94 #else
95 UNUSED2(cb);
96 UNUSED2(queueDepth);
97 #endif
98
99 return INFO::OK;
100 }
101
102 } // namespace io
103