thr_write.c revision 53812
1161196Simp/*
2157873Simp * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
3157873Simp * All rights reserved.
4157873Simp *
5157873Simp * Redistribution and use in source and binary forms, with or without
6157873Simp * modification, are permitted provided that the following conditions
7157873Simp * are met:
8157873Simp * 1. Redistributions of source code must retain the above copyright
9157873Simp *    notice, this list of conditions and the following disclaimer.
10157873Simp * 2. Redistributions in binary form must reproduce the above copyright
11157873Simp *    notice, this list of conditions and the following disclaimer in the
12157873Simp *    documentation and/or other materials provided with the distribution.
13157873Simp * 3. All advertising materials mentioning features or use of this software
14157873Simp *    must display the following acknowledgement:
15157873Simp *	This product includes software developed by John Birrell.
16157873Simp * 4. Neither the name of the author nor the names of any co-contributors
17157873Simp *    may be used to endorse or promote products derived from this software
18157873Simp *    without specific prior written permission.
19157873Simp *
20157873Simp * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21161196Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22157873Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23161196Simp * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24157873Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25157873Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26161196Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27157873Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28157873Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29157873Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30161196Simp * SUCH DAMAGE.
31157873Simp *
32161196Simp * $FreeBSD: head/lib/libkse/thread/thr_write.c 53812 1999-11-28 05:38:13Z alfred $
33157873Simp *
34163533Simp */
35163533Simp#include <sys/types.h>
36163533Simp#include <sys/fcntl.h>
37163533Simp#include <sys/uio.h>
38163533Simp#include <errno.h>
39163533Simp#include <unistd.h>
40163533Simp#ifdef _THREAD_SAFE
41161196Simp#include <pthread.h>
42157873Simp#include "pthread_private.h"
43157873Simp
44157873Simpssize_t
45157873Simpwrite(int fd, const void *buf, size_t nbytes)
46157873Simp{
47157873Simp	int	blocking;
48157873Simp	int	type;
49157873Simp	ssize_t n;
50157873Simp	ssize_t num = 0;
51157873Simp	ssize_t	ret;
52157873Simp
53157873Simp	_thread_enter_cancellation_point();
54157873Simp	/* POSIX says to do just this: */
55161196Simp	if (nbytes == 0) {
56157873Simp		_thread_leave_cancellation_point();
57157873Simp		return (0);
58157873Simp	}
59157873Simp
60161196Simp	/* Lock the file descriptor for write: */
61157873Simp	if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) {
62157873Simp		/* Get the read/write mode type: */
63161196Simp		type = _thread_fd_table[fd]->flags & O_ACCMODE;
64157873Simp
65161196Simp		/* Check if the file is not open for write: */
66157873Simp		if (type != O_WRONLY && type != O_RDWR) {
67157873Simp			/* File is not open for write: */
68157873Simp			errno = EBADF;
69157873Simp			_FD_UNLOCK(fd, FD_WRITE);
70157873Simp		_thread_leave_cancellation_point();
71157873Simp		return (-1);
72157873Simp		}
73157873Simp
74157873Simp		/* Check if file operations are to block */
75157873Simp		blocking = ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0);
76157873Simp
77157873Simp		/*
78157873Simp		 * Loop while no error occurs and until the expected number
79157873Simp		 * of bytes are written if performing a blocking write:
80157873Simp		 */
81161196Simp		while (ret == 0) {
82157873Simp			/* Perform a non-blocking write syscall: */
83161196Simp			n = _thread_sys_write(fd, buf + num, nbytes - num);
84163533Simp
85157873Simp			/* Check if one or more bytes were written: */
86157873Simp			if (n > 0)
87157873Simp				/*
88157873Simp				 * Keep a count of the number of bytes
89157873Simp				 * written:
90157873Simp				 */
91157873Simp				num += n;
92157873Simp
93163533Simp			/*
94163533Simp			 * If performing a blocking write, check if the
95157873Simp			 * write would have blocked or if some bytes
96163533Simp			 * were written but there are still more to
97161196Simp			 * write:
98157873Simp			 */
99157873Simp			if (blocking && ((n < 0 && (errno == EWOULDBLOCK ||
100157873Simp			    errno == EAGAIN)) || (n >= 0 && num < nbytes))) {
101157873Simp				_thread_run->data.fd.fd = fd;
102157873Simp				_thread_kern_set_timeout(NULL);
103157873Simp
104157873Simp				/* Reset the interrupted operation flag: */
105157873Simp				_thread_run->interrupted = 0;
106157873Simp
107157873Simp				_thread_kern_sched_state(PS_FDW_WAIT,
108157873Simp				    __FILE__, __LINE__);
109157873Simp
110157873Simp				/*
111157873Simp				 * Check if the operation was
112157873Simp				 * interrupted by a signal
113157873Simp				 */
114157873Simp				if (_thread_run->interrupted) {
115157873Simp					/* Return an error: */
116157873Simp					ret = -1;
117157873Simp				}
118157873Simp
119157873Simp			/*
120157873Simp			 * If performing a non-blocking write or if an
121163533Simp			 * error occurred, just return whatever the write
122163533Simp			 * syscall did:
123157873Simp			 */
124157873Simp			} else if (!blocking || n < 0) {
125161196Simp				/* A non-blocking call might return zero: */
126157873Simp				ret = n;
127157873Simp				break;
128157873Simp
129157873Simp			/* Check if the write has completed: */
130157873Simp			} else if (num >= nbytes)
131157873Simp				/* Return the number of bytes written: */
132157873Simp				ret = num;
133157873Simp		}
134157873Simp		_FD_UNLOCK(fd, FD_RDWR);
135157873Simp	}
136163533Simp	_thread_leave_cancellation_point();
137163533Simp	return (ret);
138161196Simp}
139161196Simp#endif
140157873Simp