xref: /dragonfly/lib/librt/aio.c (revision 783d47c4)
1 /*-
2  * Copyright (c) 2011 Venkatesh Srinivas <vsrinivas@dragonflybsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  */
15 
16 /*
17  * This file contains support for the POSIX 1003.1B AIO/LIO facility.
18  *
19  * This version of AIO is aimed at standards compliance; it is not aimed
20  * at either reasonability or performance. It merely wraps synchronous I/O
21  * routines.
22  *
23  * This version cannot perform asynchronous notification of I/O completion
24  * on DragonFly via SIGEV_SIGNAL.
25  *
26  *    2) SIGEV_SIGNAL code is present, but if-ed out under 'notyet'; Dfly
27  *	 does not support sigqueue(), so we cannot control the payload to
28  *	 a SIGINFO-signal from userspace. Programs using AIO signals use
29  *	 the payload field to carry pointers to the completed AIO structure,
30  *	 which is not yet possible here.
31  *
32  * It would be possible for this version to support SIGEV_KEVENT.
33  */
34 
35 #include <stdlib.h>
36 #include <sys/types.h>
37 #include <sys/time.h>
38 #include <sys/signal.h>
39 #include <sys/queue.h>
40 #include <unistd.h>
41 #include <errno.h>
42 #include <sys/aio.h>
43 #include <pthread.h>
44 
45 static void 	*_aio_thr_start(void *);
46 
47 static void
48 _aio_notify(struct sigevent *sigevp)
49 {
50 #if 0 /* not yet */
51 	int sig;
52 	union sigval sv;
53 	pid_t pid;
54 #endif
55 	pthread_t thr;
56 
57 	switch (sigevp->sigev_notify) {
58 	case SIGEV_NONE:
59 		return;
60 
61 	case SIGEV_THREAD:
62 		pthread_create(&thr,
63 			       sigevp->sigev_notify_attributes,
64 			       _aio_thr_start,
65 			       sigevp);
66 		break;
67 
68 	case SIGEV_SIGNAL:
69 #if 0 /* not yet */
70 		pid = getpid();
71 		sig = sigevp->sigev_signo;
72 		sv = sigevp->sigev_value;
73 		sigqueue(pid, sig, sv);
74 #endif
75 		break;
76 
77 	case SIGEV_KEVENT:
78 		/* not yet */
79 		break;
80 	}
81 }
82 
83 static void *
84 _aio_thr_start(void *vsigevp)
85 {
86 	struct sigevent *sigevp = vsigevp;
87 	sigevp->sigev_notify_function(sigevp->sigev_value);
88 	return (NULL);
89 }
90 
91 /*
92  * aio_read()
93  *
94  *	Asynchronously read from a file
95  */
96 int
97 aio_read(struct aiocb *ap)
98 {
99 #ifndef notyet
100 	if ((ap->aio_sigevent.sigev_notify != SIGEV_NONE) &&
101 	    (ap->aio_sigevent.sigev_notify != SIGEV_THREAD))
102 		return (ENOSYS);
103 #endif
104 
105 	ap->_aio_val = pread(ap->aio_fildes,
106 			     (void *) ap->aio_buf,
107 			     ap->aio_nbytes,
108 			     ap->aio_offset);
109 	ap->_aio_err = errno;
110 
111 	_aio_notify(&ap->aio_sigevent);
112 
113 	return (0);
114 }
115 
116 int
117 aio_write(struct aiocb *ap)
118 {
119 #ifndef notyet
120 	if ((ap->aio_sigevent.sigev_notify != SIGEV_NONE) &&
121 	    (ap->aio_sigevent.sigev_notify != SIGEV_THREAD))
122 		return (ENOSYS);
123 #endif
124 
125 	ap->_aio_val = pwrite(ap->aio_fildes,
126 			      (void *) ap->aio_buf,
127 			      ap->aio_nbytes,
128 			      ap->aio_offset);
129 	ap->_aio_err = errno;
130 
131 	_aio_notify(&ap->aio_sigevent);
132 
133 	return (0);
134 }
135 
136 int
137 aio_fsync(int op, struct aiocb *ap)
138 {
139 #ifndef notyet
140 	if ((ap->aio_sigevent.sigev_notify != SIGEV_NONE) &&
141 	    (ap->aio_sigevent.sigev_notify != SIGEV_THREAD))
142 		return (ENOSYS);
143 #endif
144 
145 	ap->_aio_val = fsync(ap->aio_fildes);
146 	ap->_aio_err = errno;
147 
148 	_aio_notify(&ap->aio_sigevent);
149 
150 	return(0);
151 }
152 
153 int
154 lio_listio(int mode, struct aiocb *const apv[], int nent,
155 	   struct sigevent *sigevp)
156 {
157 	int i;
158 
159 #ifndef notyet
160 	if (sigevp &&
161 	    (sigevp->sigev_notify != SIGEV_NONE) &&
162 	    (sigevp->sigev_notify != SIGEV_THREAD))
163 		return (ENOSYS);
164 #endif
165 
166 	for (i = 0; i < nent; i++)
167 		switch (apv[i]->aio_lio_opcode) {
168 		case LIO_READ:
169 			aio_read(apv[i]);
170 			break;
171 		case LIO_WRITE:
172 			aio_write(apv[i]);
173 			break;
174 		case LIO_NOP:
175 			break;
176 		}
177 
178 	if (sigevp &&
179 	    (mode == LIO_NOWAIT)
180 	   ) {
181 		_aio_notify(sigevp);
182 	}
183 
184 	return (0);
185 }
186 
187 /*
188  * aio_error()
189  *
190  * 	Get I/O completion status
191  *
192  *      Returns EINPROGRESS until I/O is complete. Returns ECANCELED if
193  *	I/O is canceled. Returns I/O status if operation completed.
194  *
195  *      This routine does not block.
196  */
197 int
198 aio_error(const struct aiocb *ap)
199 {
200 	return (ap->_aio_err);
201 }
202 
203 /*
204  * aio_return()
205  *
206  *	Finish up I/O, releasing I/O resources and returns the value
207  *	that would have been associated with a synchronous request.
208  */
209 ssize_t
210 aio_return(struct aiocb *ap)
211 {
212 	return (ap->_aio_val);
213 }
214 
215 int
216 aio_cancel(int fildes, struct aiocb *aiocbp)
217 {
218 	return (AIO_ALLDONE);
219 }
220 
221 int
222 aio_suspend(const struct aiocb *const list[], int nent, const struct timespec *timo)
223 {
224 	return (0);
225 }
226 
227