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