Merge branch 'vendor/GDTOA'
[dragonfly.git] / lib / librt / aio.c
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->sigev_notify != SIGEV_NONE) &&
161             (sigevp->sigev_notify != SIGEV_THREAD))
162                 return (ENOSYS);
163 #endif
164
165         for (i = 0; i < nent; i++)
166                 switch (apv[i]->aio_lio_opcode) {
167                 case LIO_READ:
168                         aio_read(apv[i]);
169                         break;
170                 case LIO_WRITE:
171                         aio_write(apv[i]);
172                         break;
173                 case LIO_NOP:
174                         break;
175                 }
176
177         if (sigevp && 
178             (mode == LIO_NOWAIT)
179            ) {
180                 _aio_notify(sigevp);
181         }
182
183         return (0);
184 }
185
186 /*
187  * aio_error()
188  *
189  *      Get I/O completion status
190  *
191  *      Returns EINPROGRESS until I/O is complete. Returns ECANCELED if
192  *      I/O is canceled. Returns I/O status if operation completed.
193  *
194  *      This routine does not block.
195  */
196 int 
197 aio_error(const struct aiocb *ap)
198 {
199         return (ap->_aio_err);
200 }
201
202 /*
203  * aio_return()
204  *
205  *      Finish up I/O, releasing I/O resources and returns the value
206  *      that would have been associated with a synchronous request.
207  */
208 ssize_t
209 aio_return(struct aiocb *ap)
210 {
211         return (ap->_aio_val);
212 }
213
214 int
215 aio_cancel(int fildes, struct aiocb *aiocbp)
216 {
217         return (AIO_ALLDONE);
218 }
219
220 int
221 aio_suspend(const struct aiocb *const list[], int nent, const struct timespec *timo)
222 {
223         return (0);
224 }
225