kernel - Implement ppoll system call with precise microseconds timeout.
[dragonfly.git] / lib / libthread_xu / thread / thr_syscalls.c
1 /*
2  * Copyright (C) 2005 David Xu <davidxu@freebsd.org>.
3  * Copyright (c) 2003 Daniel Eischen <deischen@freebsd.org>.
4  * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>.
5  * All rights reserved.
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice(s), this list of conditions and the following disclaimer as
12  *    the first lines of this file unmodified other than the possible
13  *    addition of one or more copyright notices.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice(s), this list of conditions and the following disclaimer in
16  *    the documentation and/or other materials provided with the
17  *    distribution.
18  * 
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
20  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
26  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
28  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
29  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $DragonFly: src/lib/libthread_xu/thread/thr_syscalls.c,v 1.8 2008/01/10 22:30:27 nth Exp $
32  */
33
34 /*
35  * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
36  * All rights reserved.
37  *
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions
40  * are met:
41  * 1. Redistributions of source code must retain the above copyright
42  *    notice, this list of conditions and the following disclaimer.
43  * 2. Redistributions in binary form must reproduce the above copyright
44  *    notice, this list of conditions and the following disclaimer in the
45  *    documentation and/or other materials provided with the distribution.
46  * 3. All advertising materials mentioning features or use of this software
47  *    must display the following acknowledgement:
48  *      This product includes software developed by John Birrell.
49  * 4. Neither the name of the author nor the names of any co-contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  *
65  */
66
67 #include <sys/types.h>
68 #include <sys/mman.h>
69 #include <sys/param.h>
70 #include <sys/select.h>
71 #include <sys/signalvar.h>
72 #include <sys/socket.h>
73 #include <sys/stat.h>
74 #include <sys/time.h>
75 #include <sys/uio.h>
76 #include <sys/wait.h>
77
78 #include <machine/tls.h>
79
80 #include <aio.h>
81 #include <dirent.h>
82 #include <errno.h>
83 #include <fcntl.h>
84 #include <poll.h>
85 #include <signal.h>
86 #include <stdarg.h>
87 #include <stdio.h>
88 #include <stdlib.h>
89 #include <string.h>
90 #include <termios.h>
91 #include <unistd.h>
92 #include <pthread.h>
93
94 #include "thr_private.h"
95
96 extern int      __creat(const char *, mode_t);
97 extern int      __pause(void);
98 extern int      __sys_pselect(int, fd_set *, fd_set *, fd_set *,
99                         const struct timespec *, const sigset_t *);
100 extern unsigned __sleep(unsigned int);
101 extern int      __system(const char *);
102 extern int      __tcdrain(int);
103 extern int      __usleep(unsigned);
104 extern pid_t    __wait(int *);
105 extern pid_t    __waitpid(pid_t, int *, int);
106 extern int      __sys_aio_suspend(const struct aiocb * const[], int,
107                         const struct timespec *);
108 extern int      __sys_accept(int, struct sockaddr *, socklen_t *);
109 extern int      __sys_connect(int, const struct sockaddr *, socklen_t);
110 extern int      __sys_fsync(int);
111 extern int      __sys_msync(void *, size_t, int);
112 extern int      __sys_poll(struct pollfd *, unsigned, int);
113 extern int      __sys_ppoll(struct pollfd *, unsigned, const struct timespec *,
114                         const sigset_t *);
115 extern ssize_t  __sys_recv(int, void *, size_t, int);
116 extern ssize_t  __sys_recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *);
117 extern ssize_t  __sys_recvmsg(int, struct msghdr *, int);
118 extern int      __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
119 extern int      __sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *,
120                         off_t *, int);
121 extern ssize_t  __sys_sendmsg(int, const struct msghdr *, int);
122 extern ssize_t  __sys_sendto(int, const void *,size_t, int, const struct sockaddr *, socklen_t);
123 extern ssize_t  __sys_readv(int, const struct iovec *, int);
124 extern pid_t    __sys_wait4(pid_t, int *, int, struct rusage *);
125 extern ssize_t  __sys_writev(int, const struct iovec *, int);
126
127 int     ___creat(const char *, mode_t);
128 int     ___usleep(unsigned);
129 int     __accept(int, struct sockaddr *, socklen_t *);
130 int     __close(int);
131 int     __connect(int, const struct sockaddr *, socklen_t);
132 int     __fcntl(int, int,...);
133 int     __fsync(int);
134 int     __msync(void *, size_t, int);
135 int     __nanosleep(const struct timespec *, struct timespec *);
136 int     __open(const char *, int,...);
137 int     __openat(int fd, const char *, int,...);
138 int     __poll(struct pollfd *, unsigned int, int);
139 int     __ppoll(struct pollfd *, unsigned int, const struct timespec *,
140                 const sigset_t *);
141 ssize_t __read(int, void *buf, size_t);
142 ssize_t __readv(int, const struct iovec *, int);
143 ssize_t __recvfrom(int, void *, size_t, int f, struct sockaddr *, socklen_t *);
144 ssize_t __recvmsg(int, struct msghdr *, int);
145 int     __select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
146 ssize_t __sendmsg(int, const struct msghdr *, int);
147 ssize_t __sendto(int, const void *, size_t, int,
148                 const struct sockaddr *, socklen_t);
149 pid_t   __wait4(pid_t, int *, int, struct rusage *);
150 ssize_t __write(int, const void *, size_t);
151 ssize_t __writev(int, const struct iovec *, int);
152 int     _aio_suspend(const struct aiocb * const iocbs[], int,
153                 const struct timespec *);
154 int     _pause(void);
155 int     __pselect(int, fd_set *, fd_set *, fd_set *,
156                 const struct timespec *, const sigset_t *);
157 int     _raise(int);
158 unsigned        _sleep(unsigned);
159 int     _system(const char *);
160 int     _tcdrain(int);
161 int     _vfork(void);
162 pid_t   _wait(int *);
163 pid_t   _waitpid(pid_t wpid, int *status, int options);
164
165 int
166 __accept(int s, struct sockaddr *addr, socklen_t *addrlen)
167 {
168         struct pthread *curthread;
169         int oldcancel;
170         int ret;
171
172         curthread = tls_get_curthread();
173         oldcancel = _thr_cancel_enter(curthread);
174         ret = __sys_accept(s, addr, addrlen);
175         _thr_cancel_leave(curthread, oldcancel);
176
177         return (ret);
178 }
179
180 __strong_reference(__accept, accept);
181
182 int
183 _aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct
184     timespec *timeout)
185 {
186         struct pthread *curthread = tls_get_curthread();
187         int oldcancel;
188         int ret;
189
190         oldcancel = _thr_cancel_enter(curthread);
191         ret = __sys_aio_suspend(iocbs, niocb, timeout);
192         _thr_cancel_leave(curthread, oldcancel);
193
194         return (ret);
195 }
196
197 __strong_reference(_aio_suspend, aio_suspend);
198
199 int
200 __close(int fd)
201 {
202         struct pthread  *curthread = tls_get_curthread();
203         int     oldcancel;
204         int     ret;
205
206         oldcancel = _thr_cancel_enter(curthread);
207         ret = __sys_close(fd);
208         _thr_cancel_leave(curthread, oldcancel);
209         
210         return (ret);
211 }
212
213 __strong_reference(__close, close);
214
215 int
216 __connect(int fd, const struct sockaddr *name, socklen_t namelen)
217 {
218         struct pthread *curthread = tls_get_curthread();
219         int oldcancel;
220         int ret;
221
222         oldcancel = _thr_cancel_enter(curthread);
223         ret = __sys_connect(fd, name, namelen);
224         _thr_cancel_leave(curthread, oldcancel);
225
226         return (ret);
227 }
228
229 __strong_reference(__connect, connect);
230
231 int
232 ___creat(const char *path, mode_t mode)
233 {
234         struct pthread *curthread = tls_get_curthread();
235         int oldcancel;
236         int ret;
237
238         oldcancel = _thr_cancel_enter(curthread);
239         ret = __creat(path, mode);
240         _thr_cancel_leave(curthread, oldcancel);
241         
242         return ret;
243 }
244
245 __strong_reference(___creat, creat);
246
247 int
248 __fcntl(int fd, int cmd,...)
249 {
250         struct pthread *curthread = tls_get_curthread();
251         int     oldcancel;
252         int     ret;
253         va_list ap;
254         
255         oldcancel = _thr_cancel_enter(curthread);
256
257         va_start(ap, cmd);
258         switch (cmd) {
259         case F_DUPFD:
260                 ret = __sys_fcntl(fd, cmd, va_arg(ap, int));
261                 break;
262         case F_SETFD:
263         case F_SETFL:
264                 ret = __sys_fcntl(fd, cmd, va_arg(ap, int));
265                 break;
266         case F_GETFD:
267         case F_GETFL:
268                 ret = __sys_fcntl(fd, cmd);
269                 break;
270         default:
271                 ret = __sys_fcntl(fd, cmd, va_arg(ap, void *));
272         }
273         va_end(ap);
274
275         _thr_cancel_leave(curthread, oldcancel);
276
277         return (ret);
278 }
279
280 __strong_reference(__fcntl, fcntl);
281
282 int
283 __fsync(int fd)
284 {
285         struct pthread *curthread = tls_get_curthread();
286         int     oldcancel;
287         int     ret;
288
289         oldcancel = _thr_cancel_enter(curthread);
290         ret = __sys_fsync(fd);
291         _thr_cancel_leave(curthread, oldcancel);
292
293         return (ret);
294 }
295
296 __strong_reference(__fsync, fsync);
297
298 int
299 __msync(void *addr, size_t len, int flags)
300 {
301         struct pthread *curthread = tls_get_curthread();
302         int     oldcancel;
303         int     ret;
304
305         oldcancel = _thr_cancel_enter(curthread);
306         ret = __sys_msync(addr, len, flags);
307         _thr_cancel_leave(curthread, oldcancel);
308
309         return ret;
310 }
311
312 __strong_reference(__msync, msync);
313
314 int
315 __nanosleep(const struct timespec *time_to_sleep,
316     struct timespec *time_remaining)
317 {
318         struct pthread *curthread = tls_get_curthread();
319         int             oldcancel;
320         int             ret;
321
322         oldcancel = _thr_cancel_enter(curthread);
323         ret = __sys_nanosleep(time_to_sleep, time_remaining);
324         _thr_cancel_leave(curthread, oldcancel);
325
326         return (ret);
327 }
328
329 __strong_reference(__nanosleep, nanosleep);
330
331 int
332 __open(const char *path, int flags,...)
333 {
334         struct pthread *curthread = tls_get_curthread();
335         int     oldcancel;
336         int     ret;
337         int     mode = 0;
338         va_list ap;
339
340         oldcancel = _thr_cancel_enter(curthread);
341         
342         /* Check if the file is being created: */
343         if (flags & O_CREAT) {
344                 /* Get the creation mode: */
345                 va_start(ap, flags);
346                 mode = va_arg(ap, int);
347                 va_end(ap);
348         }
349         
350         ret = __sys_open(path, flags, mode);
351
352         _thr_cancel_leave(curthread, oldcancel);
353
354         return ret;
355 }
356
357 __strong_reference(__open, open);
358
359 int
360 __openat(int fd, const char *path, int flags,...)
361 {
362         struct pthread *curthread = tls_get_curthread();
363         int     oldcancel;
364         int     ret;
365         int     mode = 0;
366         va_list ap;
367
368         oldcancel = _thr_cancel_enter(curthread);
369         
370         /* Check if the file is being created: */
371         if (flags & O_CREAT) {
372                 /* Get the creation mode: */
373                 va_start(ap, flags);
374                 mode = va_arg(ap, int);
375                 va_end(ap);
376         }
377         
378         ret = __sys_openat(fd, path, flags, mode);
379
380         _thr_cancel_leave(curthread, oldcancel);
381
382         return ret;
383 }
384
385 __strong_reference(__openat, openat);
386
387 int
388 _pause(void)
389 {
390         struct pthread *curthread = tls_get_curthread();
391         int     oldcancel;
392         int     ret;
393
394         oldcancel = _thr_cancel_enter(curthread);
395         ret = __pause();
396         _thr_cancel_leave(curthread, oldcancel);
397         
398         return ret;
399 }
400
401 __strong_reference(_pause, pause);
402
403 int
404 __poll(struct pollfd *fds, unsigned int nfds, int timeout)
405 {
406         struct pthread *curthread = tls_get_curthread();
407         int oldcancel;
408         int ret;
409
410         oldcancel = _thr_cancel_enter(curthread);
411         ret = __sys_poll(fds, nfds, timeout);
412         _thr_cancel_leave(curthread, oldcancel);
413
414         return ret;
415 }
416
417 __strong_reference(__poll, poll);
418
419 int
420 __ppoll(struct pollfd *fds, unsigned int nfds, const struct timespec *ts,
421         const sigset_t *mask)
422 {
423         struct pthread *curthread = tls_get_curthread();
424         int oldcancel;
425         int ret;
426
427         oldcancel = _thr_cancel_enter(curthread);
428         ret = __sys_ppoll(fds, nfds, ts, mask);
429         _thr_cancel_leave(curthread, oldcancel);
430
431         return ret;
432 }
433
434 __strong_reference(__ppoll, ppoll);
435
436 int 
437 __pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
438         const struct timespec *timo, const sigset_t *mask)
439 {
440         struct pthread *curthread = tls_get_curthread();
441         int oldcancel;
442         int ret;
443
444         oldcancel = _thr_cancel_enter(curthread);
445         ret = __sys_pselect(count, rfds, wfds, efds, timo, mask);
446         _thr_cancel_leave(curthread, oldcancel);
447
448         return (ret);
449 }
450 __strong_reference(__pselect, pselect);
451
452
453 int
454 _raise(int sig)
455 {
456         int ret;
457
458         if (!_thr_isthreaded())
459                 ret = kill(getpid(), sig);
460         else
461                 ret = _thr_send_sig(tls_get_curthread(), sig);
462         return (ret);
463 }
464
465 __strong_reference(_raise, raise);
466
467 ssize_t
468 __read(int fd, void *buf, size_t nbytes)
469 {
470         struct pthread *curthread = tls_get_curthread();
471         int oldcancel;
472         ssize_t ret;
473
474         oldcancel = _thr_cancel_enter(curthread);
475         ret = __sys_read(fd, buf, nbytes);
476         _thr_cancel_leave(curthread, oldcancel);
477
478         return ret;
479 }
480
481 __strong_reference(__read, read);
482
483 ssize_t
484 __readv(int fd, const struct iovec *iov, int iovcnt)
485 {
486         struct pthread *curthread = tls_get_curthread();
487         int oldcancel;
488         ssize_t ret;
489
490         oldcancel = _thr_cancel_enter(curthread);
491         ret = __sys_readv(fd, iov, iovcnt);
492         _thr_cancel_leave(curthread, oldcancel);
493
494         return ret;
495 }
496
497 __strong_reference(__readv, readv);
498
499 ssize_t
500 __recvfrom(int s, void *b, size_t l, int f, struct sockaddr *from,
501     socklen_t *fl)
502 {
503         struct pthread *curthread = tls_get_curthread();
504         int oldcancel;
505         ssize_t ret;
506
507         oldcancel = _thr_cancel_enter(curthread);
508         ret = __sys_recvfrom(s, b, l, f, from, fl);
509         _thr_cancel_leave(curthread, oldcancel);
510         return (ret);
511 }
512
513 __strong_reference(__recvfrom, recvfrom);
514
515 ssize_t
516 __recvmsg(int s, struct msghdr *m, int f)
517 {
518         struct pthread *curthread = tls_get_curthread();
519         ssize_t ret;
520         int oldcancel;
521
522         oldcancel = _thr_cancel_enter(curthread);
523         ret = __sys_recvmsg(s, m, f);
524         _thr_cancel_leave(curthread, oldcancel);
525         return (ret);
526 }
527
528 __strong_reference(__recvmsg, recvmsg);
529
530 int 
531 __select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
532         struct timeval *timeout)
533 {
534         struct pthread *curthread = tls_get_curthread();
535         int oldcancel;
536         int ret;
537
538         oldcancel = _thr_cancel_enter(curthread);
539         ret = __sys_select(numfds, readfds, writefds, exceptfds, timeout);
540         _thr_cancel_leave(curthread, oldcancel);
541         return ret;
542 }
543
544 __strong_reference(__select, select);
545
546 ssize_t
547 __sendmsg(int s, const struct msghdr *m, int f)
548 {
549         struct pthread *curthread = tls_get_curthread();
550         ssize_t ret;
551         int oldcancel;
552
553         oldcancel = _thr_cancel_enter(curthread);
554         ret = __sys_sendmsg(s, m, f);
555         _thr_cancel_leave(curthread, oldcancel);
556         return (ret);
557 }
558
559 __strong_reference(__sendmsg, sendmsg);
560
561 ssize_t
562 __sendto(int s, const void *m, size_t l, int f, const struct sockaddr *t,
563     socklen_t tl)
564 {
565         struct pthread *curthread = tls_get_curthread();
566         ssize_t ret;
567         int oldcancel;
568
569         oldcancel = _thr_cancel_enter(curthread);
570         ret = __sys_sendto(s, m, l, f, t, tl);
571         _thr_cancel_leave(curthread, oldcancel);
572         return (ret);
573 }
574
575 __strong_reference(__sendto, sendto);
576
577 unsigned int
578 _sleep(unsigned int seconds)
579 {
580         struct pthread *curthread = tls_get_curthread();
581         int             oldcancel;
582         unsigned int    ret;
583
584         oldcancel = _thr_cancel_enter(curthread);
585         ret = __sleep(seconds);
586         _thr_cancel_leave(curthread, oldcancel);
587         
588         return (ret);
589 }
590
591 int
592 _system(const char *string)
593 {
594         struct pthread *curthread = tls_get_curthread();
595         int     oldcancel;
596         int     ret;
597
598         oldcancel = _thr_cancel_enter(curthread);
599         ret = __system(string);
600         _thr_cancel_leave(curthread, oldcancel);
601         
602         return ret;
603 }
604
605 __strong_reference(_system, system);
606
607 int
608 _tcdrain(int fd)
609 {
610         struct pthread *curthread = tls_get_curthread();
611         int     oldcancel;
612         int     ret;
613         
614         oldcancel = _thr_cancel_enter(curthread);
615         ret = __tcdrain(fd);
616         _thr_cancel_leave(curthread, oldcancel);
617
618         return (ret);
619 }
620
621 __strong_reference(_tcdrain, tcdrain);
622
623 int
624 ___usleep(unsigned int useconds)
625 {
626         struct pthread *curthread = tls_get_curthread();
627         int             oldcancel;
628         int             ret;
629
630         oldcancel = _thr_cancel_enter(curthread);
631         ret = __usleep(useconds);
632         _thr_cancel_leave(curthread, oldcancel);
633         
634         return (ret);
635 }
636
637 __strong_reference(___usleep, usleep);
638
639 int
640 _vfork(void)
641 {
642         return (fork());
643 }
644
645 __strong_reference(_vfork, vfork);
646
647 pid_t
648 _wait(int *istat)
649 {
650         struct pthread *curthread = tls_get_curthread();
651         int     oldcancel;
652         pid_t   ret;
653
654         oldcancel = _thr_cancel_enter(curthread);
655         ret = __wait(istat);
656         _thr_cancel_leave(curthread, oldcancel);
657
658         return ret;
659 }
660
661 __strong_reference(_wait, wait);
662
663 pid_t
664 __wait4(pid_t pid, int *istat, int options, struct rusage *rusage)
665 {
666         struct pthread *curthread = tls_get_curthread();
667         int oldcancel;
668         pid_t ret;
669
670         oldcancel = _thr_cancel_enter(curthread);
671         ret = __sys_wait4(pid, istat, options, rusage);
672         _thr_cancel_leave(curthread, oldcancel);
673
674         return ret;
675 }
676
677 __strong_reference(__wait4, wait4);
678
679 pid_t
680 _waitpid(pid_t wpid, int *status, int options)
681 {
682         struct pthread *curthread = tls_get_curthread();
683         int     oldcancel;
684         pid_t   ret;
685
686         oldcancel = _thr_cancel_enter(curthread);
687         ret = __waitpid(wpid, status, options);
688         _thr_cancel_leave(curthread, oldcancel);
689         
690         return ret;
691 }
692
693 __strong_reference(_waitpid, waitpid);
694
695 ssize_t
696 __write(int fd, const void *buf, size_t nbytes)
697 {
698         struct pthread *curthread = tls_get_curthread();
699         int     oldcancel;
700         ssize_t ret;
701
702         oldcancel = _thr_cancel_enter(curthread);
703         ret = __sys_write(fd, buf, nbytes);
704         _thr_cancel_leave(curthread, oldcancel);
705
706         return ret;
707 }
708
709 __strong_reference(__write, write);
710
711 ssize_t
712 __writev(int fd, const struct iovec *iov, int iovcnt)
713 {
714         struct pthread *curthread = tls_get_curthread();
715         int     oldcancel;
716         ssize_t ret;
717
718         oldcancel = _thr_cancel_enter(curthread);
719         ret = __sys_writev(fd, iov, iovcnt);
720         _thr_cancel_leave(curthread, oldcancel);
721
722         return ret;
723 }
724
725 __strong_reference(__writev, writev);
726