Lots of new stuff in this release.
[unix-history] / lib / libpthread / pthreads / fd_pipe.c
CommitLineData
90269d47 1/* ==== fd_pipe.c ============================================================
83dfe606 2 * Copyright (c) 1993, 1994 by Chris Provenzano, proven@mit.edu
30b08b75
AM
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 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
56a62443
CP
15 * This product includes software developed by Chris Provenzano.
16 * 4. The name of Chris Provenzano may not be used to endorse or promote
17 * products derived from this software without specific prior written
18 * permission.
30b08b75 19 *
56a62443 20 * THIS SOFTWARE IS PROVIDED BY CHRIS PROVENZANO ``AS IS'' AND
30b08b75
AM
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56a62443
CP
23 * ARE DISCLAIMED. IN NO EVENT SHALL CHRIS PROVENZANO BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * Description : The new fast ITC pipe routines.
33 *
34 * 1.00 93/08/14 proven
35 * -Started coding this file.
36 *
37 * 1.01 93/11/13 proven
38 * -The functions readv() and writev() added.
30b08b75 39 */
56a62443 40
90269d47
AM
41#include <pthread.h>
42#include <pthread/fd_pipe.h>
43#include <sys/types.h>
44#include <sys/socket.h>
45#include <sys/time.h>
46#include <fcntl.h>
47#include <errno.h>
48#include <pthread/posix.h>
49
50/* ==========================================================================
51 * The pipe lock is never unlocked until all pthreads waiting are done with it
52 * read()
53 */
54ssize_t __pipe_read(struct __pipe *fd, int flags, void *buf, size_t nbytes)
55{
56 semaphore *lock, *plock;
57 int ret = 0;
58
59 if (flags & O_ACCMODE) { return(NOTOK); }
60
61 lock = &(fd->lock);
62 while (SEMAPHORE_TEST_AND_SET(lock)) {
63 pthread_yield();
64 }
65 /* If there is nothing to read, go to sleep */
66 if (fd->count == 0) {
67 if (flags == WR_CLOSED) {
68 SEMAPHORE_RESET(lock);
69 return(0);
70 } /* Lock pthread */
71 plock = &(pthread_run->lock);
72 while (SEMAPHORE_TEST_AND_SET(plock)) {
73 pthread_yield();
74 }
75
76 /* queue pthread for a FDR_WAIT */
77 pthread_run->next = NULL;
78 fd->wait = pthread_run;
79 SEMAPHORE_RESET(lock);
80 reschedule(PS_FDR_WAIT);
81 ret = fd->size;
82 } else {
83 ret = MIN(nbytes, fd->count);
84 memcpy(buf, fd->buf + fd->offset, ret);
85 if (!(fd->count -= ret)) {
86 fd->offset = 0;
87 }
88
89 /* Should try to read more from the waiting writer */
90
91 if (fd->wait) {
92 plock = &(fd->wait->lock);
93 while (SEMAPHORE_TEST_AND_SET(plock)) {
94 pthread_yield();
95 }
96 fd->wait->state = PS_RUNNING;
97 SEMAPHORE_RESET(plock);
98 } else {
99 SEMAPHORE_RESET(lock);
100 }
101 }
102 return(ret);
103}
104
105/* ==========================================================================
106 * __pipe_write()
107 *
108 * First check to see if the read side is still open, then
109 * check to see if there is a thread in a read wait for this pipe, if so
110 * copy as much data as possible directly into the read waiting threads
111 * buffer. The write thread(whether or not there was a read thread)
112 * copies as much data as it can into the pipe buffer and it there
113 * is still data it goes to sleep.
114 */
115ssize_t __pipe_write(struct __pipe *fd, int flags, const void *buf, size_t nbytes) {
116 semaphore *lock, *plock;
117 int ret, count;
118
119 if (!(flags & O_ACCMODE)) { return(NOTOK); }
120
121 lock = &(fd->lock);
122 while (SEMAPHORE_TEST_AND_SET(lock)) {
123 pthread_yield();
124 }
125 while (fd->flags != RD_CLOSED) {
126 if (fd->wait) {
127 /* Lock pthread */
128 plock = &(fd->wait->lock);
129 while (SEMAPHORE_TEST_AND_SET(plock)) {
130 pthread_yield();
131 }
132
133 /* Copy data directly into waiting pthreads buf */
134 fd->wait_size = MIN(nbytes, fd->wait_size);
135 memcpy(fd->wait_buf, buf, fd->wait_size);
136 buf = (const char *)buf + fd->wait_size;
137 nbytes -= fd->wait_size;
138 ret = fd->wait_size;
139
140 /* Wake up waiting pthread */
141 fd->wait->state = PS_RUNNING;
142 SEMAPHORE_RESET(plock);
143 fd->wait = NULL;
144 }
145
146 if (count = MIN(nbytes, fd->size - (fd->offset + fd->count))) {
147 memcpy(fd->buf + (fd->offset + fd->count), buf, count);
148 buf = (const char *)buf + count;
149 nbytes -= count;
150 ret += count;
151 }
152 if (nbytes) {
153 /* Lock pthread */
154 plock = &(fd->wait->lock);
155 while (SEMAPHORE_TEST_AND_SET(plock)) {
156 pthread_yield();
157 }
158
159 fd->wait = pthread_run;
160 SEMAPHORE_RESET(lock);
161 reschedule(PS_FDW_WAIT);
162 } else {
163 return(ret);
164 }
165 }
166 return(NOTOK);
167}
168
169/* ==========================================================================
170 * __pipe_close()
171 *
172 * The whole close procedure is a bit odd and needs a bit of a rethink.
173 * For now close() locks the fd, calls fd_free() which checks to see if
174 * there are any other fd values poinging to the same real fd. If so
175 * It breaks the wait queue into two sections those that are waiting on fd
176 * and those waiting on other fd's. Those that are waiting on fd are connected
177 * to the fd_table[fd] queue, and the count is set to zero, (BUT THE LOCK IS NOT
178 * RELEASED). close() then calls fd_unlock which give the fd to the next queued
179 * element which determins that the fd is closed and then calls fd_unlock etc...
180 */
181int __pipe_close(struct __pipe *fd, int flags)
182{
183 semaphore *lock, *plock;
184
185 lock = &(fd->lock);
186 while (SEMAPHORE_TEST_AND_SET(lock)) {
187 pthread_yield();
188 }
189 if (!(fd->flags)) {
190 if (fd->wait) {
191 if (flags & O_ACCMODE) {
192 fd->flags |= WR_CLOSED;
193 /* Lock pthread */
194 /* Write side closed, wake read side and return EOF */
195 plock = &((fd->wait)->lock);
196 while (SEMAPHORE_TEST_AND_SET(plock)) {
197 pthread_yield();
198 }
199
200 fd->count = 0;
201
202 /* Wake up waiting pthread */
203 fd->wait->state = PS_RUNNING;
204 SEMAPHORE_RESET(plock);
205 fd->wait = NULL;
206 } else {
207 /* Should send a signal */
208 fd->flags |= RD_CLOSED;
209 }
210 }
211 } else {
212 free(fd);
213 return(OK);
214 }
215 SEMAPHORE_RESET(lock);
216}
217
218/* ==========================================================================
219 * For those function that aren't implemented yet
220 * __pipe_enosys()
221 */
222static int __pipe_enosys()
223{
224 pthread_run->error = ENOSYS;
225 return(NOTOK);
226}
227
228/*
229 * File descriptor operations
230 */
231struct fd_ops fd_ops[] = {
232{ NULL, NULL, }, /* Non operations */
233{ __pipe_write, __pipe_read, __pipe_close, __pipe_enosys, __pipe_enosys,
234 __pipe_enosys },
235};
236
237/* ==========================================================================
238 * open()
239 */
240/* int __pipe_open(const char *path, int flags, ...) */
241int newpipe(int fd[2])
242{
243 struct __pipe *fd_data;
244
245 if ((!((fd[0] = fd_allocate()) < OK)) && (!((fd[1] = fd_allocate()) < OK))) {
246 fd_data = malloc(sizeof(struct __pipe));
247 fd_data->buf = malloc(4096);
248 fd_data->size = 4096;
249 fd_data->count = 0;
250 fd_data->offset = 0;
251
252 fd_data->wait = NULL;
253 fd_data->flags = 0;
254
255 fd_table[fd[0]]->fd.ptr = fd_data;
256 fd_table[fd[0]]->flags = O_RDONLY;
257 fd_table[fd[1]]->fd.ptr = fd_data;
258 fd_table[fd[1]]->flags = O_WRONLY;
259
260 return(OK);
261 }
262 return(NOTOK);
263}
264