xref: /dragonfly/lib/librt/aio.c (revision cfd1aba3)
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 <sys/stat.h>
41 #include <unistd.h>
42 #include <errno.h>
43 #include <sys/aio.h>
44 #include <pthread.h>
45 
46 static void 	*_aio_thr_start(void *);
47 
48 static void
49 _aio_notify(struct sigevent *sigevp)
50 {
51 #if 0 /* not yet */
52 	int sig;
53 	union sigval sv;
54 	pid_t pid;
55 #endif
56 	pthread_t thr;
57 
58 	switch (sigevp->sigev_notify) {
59 	case SIGEV_NONE:
60 		return;
61 
62 	case SIGEV_THREAD:
63 		pthread_create(&thr,
64 			       sigevp->sigev_notify_attributes,
65 			       _aio_thr_start,
66 			       sigevp);
67 		break;
68 
69 	case SIGEV_SIGNAL:
70 #if 0 /* not yet */
71 		pid = getpid();
72 		sig = sigevp->sigev_signo;
73 		sv = sigevp->sigev_value;
74 		sigqueue(pid, sig, sv);
75 #endif
76 		break;
77 
78 	case SIGEV_KEVENT:
79 		/* not yet */
80 		break;
81 	}
82 }
83 
84 static void *
85 _aio_thr_start(void *vsigevp)
86 {
87 	struct sigevent *sigevp = vsigevp;
88 	sigevp->sigev_notify_function(sigevp->sigev_value);
89 	return (NULL);
90 }
91 
92 /*
93  * aio_read()
94  *
95  *	Asynchronously read from a file
96  */
97 int
98 aio_read(struct aiocb *ap)
99 {
100 #ifndef notyet
101 	if ((ap->aio_sigevent.sigev_notify != SIGEV_NONE) &&
102 	    (ap->aio_sigevent.sigev_notify != SIGEV_THREAD))
103 		return (ENOSYS);
104 #endif
105 
106 	ap->_aio_val = pread(ap->aio_fildes,
107 			     (void *) ap->aio_buf,
108 			     ap->aio_nbytes,
109 			     ap->aio_offset);
110 	ap->_aio_err = errno;
111 
112 	_aio_notify(&ap->aio_sigevent);
113 
114 	return (0);
115 }
116 
117 int
118 aio_write(struct aiocb *ap)
119 {
120 #ifndef notyet
121 	if ((ap->aio_sigevent.sigev_notify != SIGEV_NONE) &&
122 	    (ap->aio_sigevent.sigev_notify != SIGEV_THREAD))
123 		return (ENOSYS);
124 #endif
125 
126 	ap->_aio_val = pwrite(ap->aio_fildes,
127 			      (void *) ap->aio_buf,
128 			      ap->aio_nbytes,
129 			      ap->aio_offset);
130 	ap->_aio_err = errno;
131 
132 	_aio_notify(&ap->aio_sigevent);
133 
134 	return (0);
135 }
136 
137 int
138 aio_fsync(int op, struct aiocb *ap)
139 {
140 #ifndef notyet
141 	if ((ap->aio_sigevent.sigev_notify != SIGEV_NONE) &&
142 	    (ap->aio_sigevent.sigev_notify != SIGEV_THREAD))
143 		return (ENOSYS);
144 #endif
145 
146 	ap->_aio_val = fsync(ap->aio_fildes);
147 	ap->_aio_err = errno;
148 
149 	_aio_notify(&ap->aio_sigevent);
150 
151 	return(0);
152 }
153 
154 int
155 lio_listio(int mode, struct aiocb *const apv[], int nent,
156 	   struct sigevent *sigevp)
157 {
158 	int i;
159 
160 #ifndef notyet
161 	if (sigevp &&
162 	    (sigevp->sigev_notify != SIGEV_NONE) &&
163 	    (sigevp->sigev_notify != SIGEV_THREAD))
164 		return (ENOSYS);
165 #endif
166 
167 	for (i = 0; i < nent; i++)
168 		switch (apv[i]->aio_lio_opcode) {
169 		case LIO_READ:
170 			aio_read(apv[i]);
171 			break;
172 		case LIO_WRITE:
173 			aio_write(apv[i]);
174 			break;
175 		case LIO_NOP:
176 			break;
177 		}
178 
179 	if (sigevp &&
180 	    (mode == LIO_NOWAIT)
181 	   ) {
182 		_aio_notify(sigevp);
183 	}
184 
185 	return (0);
186 }
187 
188 /*
189  * aio_error()
190  *
191  * 	Get I/O completion status
192  *
193  *      Returns EINPROGRESS until I/O is complete. Returns ECANCELED if
194  *	I/O is canceled. Returns I/O status if operation completed.
195  *
196  *      This routine does not block.
197  */
198 int
199 aio_error(const struct aiocb *ap)
200 {
201 	return (ap->_aio_err);
202 }
203 
204 /*
205  * aio_return()
206  *
207  *	Finish up I/O, releasing I/O resources and returns the value
208  *	that would have been associated with a synchronous request.
209  */
210 ssize_t
211 aio_return(struct aiocb *ap)
212 {
213 	return (ap->_aio_val);
214 }
215 
216 int
217 aio_cancel(int fildes, struct aiocb *aiocbp)
218 {
219 	struct stat sb;
220 
221 	/* must be a valid file descriptor */
222 	if (fstat(fildes, &sb)) {
223 		errno = EBADF;
224 		return -1;
225 	}
226 	return (AIO_ALLDONE);
227 }
228 
229 int
230 aio_suspend(const struct aiocb *const list[], int nent, const struct timespec *timo)
231 {
232 	return (0);
233 }
234 
235