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 * $FreeBSD$
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. Neither the name of the author nor the names of any co-contributors
47 *    may be used to endorse or promote products derived from this software
48 *    without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 *
62 */
63
64#include "namespace.h"
65#include <sys/types.h>
66#include <sys/mman.h>
67#include <sys/param.h>
68#include <sys/select.h>
69#include <sys/signalvar.h>
70#include <sys/socket.h>
71#include <sys/stat.h>
72#include <sys/time.h>
73#include <sys/uio.h>
74#include <sys/wait.h>
75#include <aio.h>
76#include <dirent.h>
77#include <errno.h>
78#include <fcntl.h>
79#include <poll.h>
80#include <signal.h>
81#include <stdarg.h>
82#include <stdio.h>
83#include <stdlib.h>
84#include <string.h>
85#include <termios.h>
86#include <unistd.h>
87#include <pthread.h>
88#include "un-namespace.h"
89
90#include "thr_private.h"
91
92extern int	__creat(const char *, mode_t);
93extern int	__pselect(int, fd_set *, fd_set *, fd_set *,
94			const struct timespec *, const sigset_t *);
95extern unsigned	__sleep(unsigned int);
96extern int	__system(const char *);
97extern int	__tcdrain(int);
98extern int	__usleep(useconds_t);
99extern pid_t	__wait(int *);
100extern pid_t	__waitpid(pid_t, int *, int);
101extern int	__sys_aio_suspend(const struct aiocb * const[], int,
102			const struct timespec *);
103extern int	__sys_accept(int, struct sockaddr *, socklen_t *);
104extern int	__sys_connect(int, const struct sockaddr *, socklen_t);
105extern int	__sys_fsync(int);
106extern int	__sys_msync(void *, size_t, int);
107extern int	__sys_pselect(int, fd_set *, fd_set *, fd_set *,
108			const struct timespec *, const sigset_t *);
109extern int	__sys_poll(struct pollfd *, unsigned, int);
110extern ssize_t	__sys_recv(int, void *, size_t, int);
111extern ssize_t	__sys_recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *);
112extern ssize_t	__sys_recvmsg(int, struct msghdr *, int);
113extern int	__sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
114extern int	__sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *,
115			off_t *, int);
116extern ssize_t	__sys_sendmsg(int, const struct msghdr *, int);
117extern ssize_t	__sys_sendto(int, const void *,size_t, int, const struct sockaddr *, socklen_t);
118extern ssize_t	__sys_readv(int, const struct iovec *, int);
119extern pid_t	__sys_wait4(pid_t, int *, int, struct rusage *);
120extern ssize_t	__sys_writev(int, const struct iovec *, int);
121
122int	___creat(const char *, mode_t);
123int	___pselect(int, fd_set *, fd_set *, fd_set *,
124		const struct timespec *, const sigset_t *);
125unsigned	___sleep(unsigned);
126int	___system(const char *);
127int	___tcdrain(int);
128int	___usleep(useconds_t useconds);
129pid_t	___wait(int *);
130pid_t	___waitpid(pid_t, int *, int);
131int	__accept(int, struct sockaddr *, socklen_t *);
132int	__aio_suspend(const struct aiocb * const iocbs[], int,
133		const struct timespec *);
134int	__close(int);
135int	__connect(int, const struct sockaddr *, socklen_t);
136int	__fcntl(int, int,...);
137#ifdef SYSCALL_COMPAT
138extern int __fcntl_compat(int, int,...);
139#endif
140int	__fsync(int);
141int	__msync(void *, size_t, int);
142int	__nanosleep(const struct timespec *, struct timespec *);
143int	__open(const char *, int,...);
144int	__openat(int, const char *, int,...);
145int	__poll(struct pollfd *, unsigned int, int);
146ssize_t	__read(int, void *buf, size_t);
147ssize_t	__readv(int, const struct iovec *, int);
148ssize_t	__recvfrom(int, void *, size_t, int f, struct sockaddr *, socklen_t *);
149ssize_t	__recvmsg(int, struct msghdr *, int);
150int	__select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
151ssize_t	__sendmsg(int, const struct msghdr *, int);
152ssize_t	__sendto(int, const void *, size_t, int,
153		const struct sockaddr *, socklen_t);
154pid_t	__wait3(int *, int, struct rusage *);
155pid_t	__wait4(pid_t, int *, int, struct rusage *);
156ssize_t	__write(int, const void *, size_t);
157ssize_t	__writev(int, const struct iovec *, int);
158
159__weak_reference(__accept, accept);
160
161/*
162 * Cancellation behavior:
163 *   If thread is canceled, no socket is created.
164 */
165int
166__accept(int s, struct sockaddr *addr, socklen_t *addrlen)
167{
168	struct pthread *curthread;
169	int ret;
170
171	curthread = _get_curthread();
172	_thr_cancel_enter(curthread);
173	ret = __sys_accept(s, addr, addrlen);
174	_thr_cancel_leave(curthread, ret == -1);
175
176 	return (ret);
177}
178
179__weak_reference(__aio_suspend, aio_suspend);
180
181int
182__aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct
183    timespec *timeout)
184{
185	struct pthread *curthread = _get_curthread();
186	int ret;
187
188	_thr_cancel_enter(curthread);
189	ret = __sys_aio_suspend(iocbs, niocb, timeout);
190	_thr_cancel_leave(curthread, 1);
191
192	return (ret);
193}
194
195__weak_reference(__close, close);
196
197/*
198 * Cancellation behavior:
199 *   According to manual of close(), the file descriptor is always deleted.
200 *   Here, thread is only canceled after the system call, so the file
201 *   descriptor is always deleted despite whether the thread is canceled
202 *   or not.
203 */
204int
205__close(int fd)
206{
207	struct pthread	*curthread = _get_curthread();
208	int	ret;
209
210	_thr_cancel_enter2(curthread, 0);
211	ret = __sys_close(fd);
212	_thr_cancel_leave(curthread, 1);
213
214	return (ret);
215}
216
217__weak_reference(__connect, connect);
218
219/*
220 * Cancellation behavior:
221 *   If the thread is canceled, connection is not made.
222 */
223int
224__connect(int fd, const struct sockaddr *name, socklen_t namelen)
225{
226	struct pthread *curthread = _get_curthread();
227	int ret;
228
229	_thr_cancel_enter(curthread);
230	ret = __sys_connect(fd, name, namelen);
231	_thr_cancel_leave(curthread, ret == -1);
232
233 	return (ret);
234}
235
236__weak_reference(___creat, creat);
237
238/*
239 * Cancellation behavior:
240 *   If thread is canceled, file is not created.
241 */
242int
243___creat(const char *path, mode_t mode)
244{
245	struct pthread *curthread = _get_curthread();
246	int ret;
247
248	_thr_cancel_enter(curthread);
249	ret = __creat(path, mode);
250	_thr_cancel_leave(curthread, ret == -1);
251
252	return ret;
253}
254
255__weak_reference(__fcntl, fcntl);
256
257/*
258 * Cancellation behavior:
259 *   According to specification, only F_SETLKW is a cancellation point.
260 *   Thread is only canceled at start, or canceled if the system call
261 *   is failure, this means the function does not generate side effect
262 *   if it is canceled.
263 */
264int
265__fcntl(int fd, int cmd,...)
266{
267	struct pthread *curthread = _get_curthread();
268	int	ret;
269	va_list	ap;
270
271	va_start(ap, cmd);
272	if (cmd == F_OSETLKW || cmd == F_SETLKW) {
273		_thr_cancel_enter(curthread);
274#ifdef SYSCALL_COMPAT
275		ret = __fcntl_compat(fd, cmd, va_arg(ap, void *));
276#else
277		ret = __sys_fcntl(fd, cmd, va_arg(ap, void *));
278#endif
279		_thr_cancel_leave(curthread, ret == -1);
280	} else {
281#ifdef SYSCALL_COMPAT
282		ret = __fcntl_compat(fd, cmd, va_arg(ap, void *));
283#else
284		ret = __sys_fcntl(fd, cmd, va_arg(ap, void *));
285#endif
286	}
287	va_end(ap);
288
289	return (ret);
290}
291
292__weak_reference(__fsync, fsync);
293
294/*
295 * Cancellation behavior:
296 *   Thread may be canceled after system call.
297 */
298int
299__fsync(int fd)
300{
301	struct pthread *curthread = _get_curthread();
302	int	ret;
303
304	_thr_cancel_enter2(curthread, 0);
305	ret = __sys_fsync(fd);
306	_thr_cancel_leave(curthread, 1);
307
308	return (ret);
309}
310
311__weak_reference(__msync, msync);
312
313/*
314 * Cancellation behavior:
315 *   Thread may be canceled after system call.
316 */
317int
318__msync(void *addr, size_t len, int flags)
319{
320	struct pthread *curthread = _get_curthread();
321	int	ret;
322
323	_thr_cancel_enter2(curthread, 0);
324	ret = __sys_msync(addr, len, flags);
325	_thr_cancel_leave(curthread, 1);
326
327	return ret;
328}
329
330__weak_reference(__nanosleep, nanosleep);
331
332int
333__nanosleep(const struct timespec *time_to_sleep,
334    struct timespec *time_remaining)
335{
336	struct pthread *curthread = _get_curthread();
337	int		ret;
338
339	_thr_cancel_enter(curthread);
340	ret = __sys_nanosleep(time_to_sleep, time_remaining);
341	_thr_cancel_leave(curthread, 1);
342
343	return (ret);
344}
345
346__weak_reference(__open, open);
347
348/*
349 * Cancellation behavior:
350 *   If the thread is canceled, file is not opened.
351 */
352int
353__open(const char *path, int flags,...)
354{
355	struct pthread *curthread = _get_curthread();
356	int	ret;
357	int	mode = 0;
358	va_list	ap;
359
360	/* Check if the file is being created: */
361	if (flags & O_CREAT) {
362		/* Get the creation mode: */
363		va_start(ap, flags);
364		mode = va_arg(ap, int);
365		va_end(ap);
366	}
367
368	_thr_cancel_enter(curthread);
369	ret = __sys_open(path, flags, mode);
370	_thr_cancel_leave(curthread, ret == -1);
371
372	return ret;
373}
374
375__weak_reference(__openat, openat);
376
377/*
378 * Cancellation behavior:
379 *   If the thread is canceled, file is not opened.
380 */
381int
382__openat(int fd, const char *path, int flags, ...)
383{
384	struct pthread *curthread = _get_curthread();
385	int	ret;
386	int	mode = 0;
387	va_list	ap;
388
389
390	/* Check if the file is being created: */
391	if (flags & O_CREAT) {
392		/* Get the creation mode: */
393		va_start(ap, flags);
394		mode = va_arg(ap, int);
395		va_end(ap);
396	}
397
398	_thr_cancel_enter(curthread);
399	ret = __sys_openat(fd, path, flags, mode);
400	_thr_cancel_leave(curthread, ret == -1);
401
402	return ret;
403}
404
405__weak_reference(__poll, poll);
406
407/*
408 * Cancellation behavior:
409 *   Thread may be canceled at start, but if the system call returns something,
410 *   the thread is not canceled.
411 */
412int
413__poll(struct pollfd *fds, unsigned int nfds, int timeout)
414{
415	struct pthread *curthread = _get_curthread();
416	int ret;
417
418	_thr_cancel_enter(curthread);
419	ret = __sys_poll(fds, nfds, timeout);
420	_thr_cancel_leave(curthread, ret == -1);
421
422	return ret;
423}
424
425__weak_reference(___pselect, pselect);
426
427/*
428 * Cancellation behavior:
429 *   Thread may be canceled at start, but if the system call returns something,
430 *   the thread is not canceled.
431 */
432int
433___pselect(int count, fd_set *rfds, fd_set *wfds, fd_set *efds,
434	const struct timespec *timo, const sigset_t *mask)
435{
436	struct pthread *curthread = _get_curthread();
437	int ret;
438
439	_thr_cancel_enter(curthread);
440	ret = __sys_pselect(count, rfds, wfds, efds, timo, mask);
441	_thr_cancel_leave(curthread, ret == -1);
442
443	return (ret);
444}
445
446__weak_reference(__read, read);
447
448/*
449 * Cancellation behavior:
450 *   Thread may be canceled at start, but if the system call got some data,
451 *   the thread is not canceled.
452 */
453ssize_t
454__read(int fd, void *buf, size_t nbytes)
455{
456	struct pthread *curthread = _get_curthread();
457	ssize_t	ret;
458
459	_thr_cancel_enter(curthread);
460	ret = __sys_read(fd, buf, nbytes);
461	_thr_cancel_leave(curthread, ret == -1);
462
463	return ret;
464}
465
466__weak_reference(__readv, readv);
467
468/*
469 * Cancellation behavior:
470 *   Thread may be canceled at start, but if the system call got some data,
471 *   the thread is not canceled.
472 */
473ssize_t
474__readv(int fd, const struct iovec *iov, int iovcnt)
475{
476	struct pthread *curthread = _get_curthread();
477	ssize_t ret;
478
479	_thr_cancel_enter(curthread);
480	ret = __sys_readv(fd, iov, iovcnt);
481	_thr_cancel_leave(curthread, ret == -1);
482	return ret;
483}
484
485__weak_reference(__recvfrom, recvfrom);
486
487/*
488 * Cancellation behavior:
489 *   Thread may be canceled at start, but if the system call got some data,
490 *   the thread is not canceled.
491 */
492ssize_t
493__recvfrom(int s, void *b, size_t l, int f, struct sockaddr *from,
494    socklen_t *fl)
495{
496	struct pthread *curthread = _get_curthread();
497	ssize_t ret;
498
499	_thr_cancel_enter(curthread);
500	ret = __sys_recvfrom(s, b, l, f, from, fl);
501	_thr_cancel_leave(curthread, ret == -1);
502	return (ret);
503}
504
505__weak_reference(__recvmsg, recvmsg);
506
507/*
508 * Cancellation behavior:
509 *   Thread may be canceled at start, but if the system call got some data,
510 *   the thread is not canceled.
511 */
512ssize_t
513__recvmsg(int s, struct msghdr *m, int f)
514{
515	struct pthread *curthread = _get_curthread();
516	ssize_t ret;
517
518	_thr_cancel_enter(curthread);
519	ret = __sys_recvmsg(s, m, f);
520	_thr_cancel_leave(curthread, ret == -1);
521	return (ret);
522}
523
524__weak_reference(__select, select);
525
526/*
527 * Cancellation behavior:
528 *   Thread may be canceled at start, but if the system call returns something,
529 *   the thread is not canceled.
530 */
531int
532__select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
533	struct timeval *timeout)
534{
535	struct pthread *curthread = _get_curthread();
536	int ret;
537
538	_thr_cancel_enter(curthread);
539	ret = __sys_select(numfds, readfds, writefds, exceptfds, timeout);
540	_thr_cancel_leave(curthread, ret == -1);
541	return ret;
542}
543
544__weak_reference(__sendmsg, sendmsg);
545
546/*
547 * Cancellation behavior:
548 *   Thread may be canceled at start, but if the system call sent
549 *   data, the thread is not canceled.
550 */
551ssize_t
552__sendmsg(int s, const struct msghdr *m, int f)
553{
554	struct pthread *curthread = _get_curthread();
555	ssize_t ret;
556
557	_thr_cancel_enter(curthread);
558	ret = __sys_sendmsg(s, m, f);
559	_thr_cancel_leave(curthread, ret <= 0);
560	return (ret);
561}
562
563__weak_reference(__sendto, sendto);
564
565/*
566 * Cancellation behavior:
567 *   Thread may be canceled at start, but if the system call sent some
568 *   data, the thread is not canceled.
569 */
570ssize_t
571__sendto(int s, const void *m, size_t l, int f, const struct sockaddr *t,
572    socklen_t tl)
573{
574	struct pthread *curthread = _get_curthread();
575	ssize_t ret;
576
577	_thr_cancel_enter(curthread);
578	ret = __sys_sendto(s, m, l, f, t, tl);
579	_thr_cancel_leave(curthread, ret <= 0);
580	return (ret);
581}
582
583__weak_reference(___sleep, sleep);
584
585unsigned int
586___sleep(unsigned int seconds)
587{
588	struct pthread *curthread = _get_curthread();
589	unsigned int	ret;
590
591	_thr_cancel_enter(curthread);
592	ret = __sleep(seconds);
593	_thr_cancel_leave(curthread, 1);
594
595	return (ret);
596}
597
598__weak_reference(___system, system);
599
600int
601___system(const char *string)
602{
603	struct pthread *curthread = _get_curthread();
604	int	ret;
605
606	_thr_cancel_enter(curthread);
607	ret = __system(string);
608	_thr_cancel_leave(curthread, 1);
609
610	return ret;
611}
612
613__weak_reference(___tcdrain, tcdrain);
614
615/*
616 * Cancellation behavior:
617 *   If thread is canceled, the system call is not completed,
618 *   this means not all bytes were drained.
619 */
620int
621___tcdrain(int fd)
622{
623	struct pthread *curthread = _get_curthread();
624	int	ret;
625
626	_thr_cancel_enter(curthread);
627	ret = __tcdrain(fd);
628	_thr_cancel_leave(curthread, ret == -1);
629	return (ret);
630}
631
632__weak_reference(___usleep, usleep);
633
634int
635___usleep(useconds_t useconds)
636{
637	struct pthread *curthread = _get_curthread();
638	int		ret;
639
640	_thr_cancel_enter(curthread);
641	ret = __usleep(useconds);
642	_thr_cancel_leave(curthread, 1);
643
644	return (ret);
645}
646
647__weak_reference(___wait, wait);
648
649/*
650 * Cancellation behavior:
651 *   Thread may be canceled at start, but if the system call returns
652 *   a child pid, the thread is not canceled.
653 */
654pid_t
655___wait(int *istat)
656{
657	struct pthread *curthread = _get_curthread();
658	pid_t	ret;
659
660	_thr_cancel_enter(curthread);
661	ret = __wait(istat);
662	_thr_cancel_leave(curthread, ret <= 0);
663
664	return ret;
665}
666
667__weak_reference(__wait3, wait3);
668
669/*
670 * Cancellation behavior:
671 *   Thread may be canceled at start, but if the system call returns
672 *   a child pid, the thread is not canceled.
673 */
674pid_t
675__wait3(int *status, int options, struct rusage *rusage)
676{
677	struct pthread *curthread = _get_curthread();
678	pid_t ret;
679
680	_thr_cancel_enter(curthread);
681	ret = _wait4(WAIT_ANY, status, options, rusage);
682	_thr_cancel_leave(curthread, ret <= 0);
683
684	return (ret);
685}
686
687__weak_reference(__wait4, wait4);
688
689/*
690 * Cancellation behavior:
691 *   Thread may be canceled at start, but if the system call returns
692 *   a child pid, the thread is not canceled.
693 */
694pid_t
695__wait4(pid_t pid, int *status, int options, struct rusage *rusage)
696{
697	struct pthread *curthread = _get_curthread();
698	pid_t ret;
699
700	_thr_cancel_enter(curthread);
701	ret = __sys_wait4(pid, status, options, rusage);
702	_thr_cancel_leave(curthread, ret <= 0);
703
704	return ret;
705}
706
707__weak_reference(___waitpid, waitpid);
708
709/*
710 * Cancellation behavior:
711 *   Thread may be canceled at start, but if the system call returns
712 *   a child pid, the thread is not canceled.
713 */
714pid_t
715___waitpid(pid_t wpid, int *status, int options)
716{
717	struct pthread *curthread = _get_curthread();
718	pid_t	ret;
719
720	_thr_cancel_enter(curthread);
721	ret = __waitpid(wpid, status, options);
722	_thr_cancel_leave(curthread, ret <= 0);
723
724	return ret;
725}
726
727__weak_reference(__write, write);
728
729/*
730 * Cancellation behavior:
731 *   Thread may be canceled at start, but if the thread wrote some data,
732 *   it is not canceled.
733 */
734ssize_t
735__write(int fd, const void *buf, size_t nbytes)
736{
737	struct pthread *curthread = _get_curthread();
738	ssize_t	ret;
739
740	_thr_cancel_enter(curthread);
741	ret = __sys_write(fd, buf, nbytes);
742	_thr_cancel_leave(curthread, (ret <= 0));
743	return ret;
744}
745
746__weak_reference(__writev, writev);
747
748/*
749 * Cancellation behavior:
750 *   Thread may be canceled at start, but if the thread wrote some data,
751 *   it is not canceled.
752 */
753ssize_t
754__writev(int fd, const struct iovec *iov, int iovcnt)
755{
756	struct pthread *curthread = _get_curthread();
757	ssize_t ret;
758
759	_thr_cancel_enter(curthread);
760	ret = __sys_writev(fd, iov, iovcnt);
761	_thr_cancel_leave(curthread, (ret <= 0));
762	return ret;
763}
764