IBNOS
pipe.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, Michael Müller
3  * Copyright (c) 2014, Sebastian Lackner
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright notice, this
10  * list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions and the following disclaimer in the documentation
13  * and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  */
27 
28 #include <process/pipe.h>
29 #include <process/object.h>
30 #include <memory/allocator.h>
31 #include <console/console.h>
32 #include <util/list.h>
33 #include <util/util.h>
34 
41 #define MIN_PIPE_BUFFER_SIZE 0x1000
42 #define MAX_PIPE_BUFFER_SIZE 0x10000
43 
44 static void __pipeDestroy(struct object *obj);
45 static uint32_t __pipeGetMinHandle(UNUSED struct object *obj);
46 static void __pipeShutdown(struct object *obj, uint32_t mode);
47 static int32_t __pipeGetStatus(struct object *obj, uint32_t mode);
48 static struct linkedList *__pipeWait(struct object *obj, uint32_t mode, uint32_t *result);
49 static int32_t __pipeWrite(struct object *obj, uint8_t *buf, uint32_t length);
50 static int32_t __pipeRead(struct object *obj, uint8_t *buf, uint32_t length);
51 
52 static const struct objectFunctions pipeFunctions =
53 {
54  __pipeDestroy,
55  __pipeGetMinHandle,
56  __pipeShutdown,
57  __pipeGetStatus,
58  __pipeWait,
59  NULL, /* signal */
60  __pipeWrite,
61  __pipeRead,
62  NULL, /* insert */
63  NULL, /* remove */
64 };
65 
66 static void __stdoutDestroy(struct object *obj);
67 static uint32_t __stdoutGetMinHandle(UNUSED struct object *obj);
68 static int32_t __stdoutWrite(UNUSED struct object *obj, uint8_t *buf, uint32_t length);
69 
70 static const struct objectFunctions stdoutFunctions =
71 {
72  __stdoutDestroy,
73  __stdoutGetMinHandle,
74  NULL, /* getMinHandle */
75  NULL, /* shutdown */
76  NULL, /* wait */
77  NULL, /* signal */
78  __stdoutWrite,
79  NULL, /* read */
80  NULL, /* insert */
81  NULL, /* remove */
82 };
83 
88 struct pipe *pipeCreate()
89 {
90  struct pipe *p;
91  uint8_t *buffer;
92 
93  /* allocate some new memory */
94  if (!(p = heapAlloc(sizeof(*p))))
95  return NULL;
96 
97  if (!(buffer = heapAlloc(MIN_PIPE_BUFFER_SIZE)))
98  {
99  heapFree(p);
100  return NULL;
101  }
102 
103  /* initialize general object info */
104  __objectInit(&p->obj, &pipeFunctions);
105  ll_init(&p->writeWaiters);
106  ll_init(&p->readWaiters);
107  p->buffer = buffer;
109  p->writePos = 0;
110  p->readPos = 0;
111  p->writeable = true;
112 
113  return p;
114 }
115 
121 static void __pipeDestroy(struct object *obj)
122 {
123  struct pipe *p = objectContainer(obj, struct pipe, &pipeFunctions);
124 
125  /* release other threads if the user destroys the object before they return */
126  queueWakeup(&p->writeWaiters, true, -1);
127  queueWakeup(&p->readWaiters, true, -1);
128  assert(ll_empty(&p->writeWaiters));
129  assert(ll_empty(&p->readWaiters));
130 
131  /* release buffer, even if it still contains data */
132  if (p->buffer) heapFree(p->buffer);
133 
134  /* release pipe memory */
135  p->obj.functions = NULL;
136  heapFree(p);
137 }
138 
145 static uint32_t __pipeGetMinHandle(UNUSED struct object *obj)
146 {
147  /* pipe numbers can start from zero */
148  return 0;
149 }
150 
163 static void __pipeShutdown(struct object *obj, uint32_t mode)
164 {
165  struct pipe *p = objectContainer(obj, struct pipe, &pipeFunctions);
166 
167  /* write will be closed anyway */
168  p->writeable = false;
169  queueWakeup(&p->writeWaiters, true, -1);
170 
171  /* close only write mode, and the pipe is not yet empty */
172  if (mode && p->writePos != p->readPos) return;
173 
174  /* close read mode */
175  queueWakeup(&p->readWaiters, true, -1);
176 
177  /* release buffer and reset internal structure */
178  if (p->buffer) heapFree(p->buffer);
179  p->buffer = NULL;
180  p->size = 0;
181  p->writePos = 0;
182  p->readPos = 0;
183 }
184 
197 static int32_t __pipeGetStatus(struct object *obj, uint32_t mode)
198 {
199  struct pipe *p = objectContainer(obj, struct pipe, &pipeFunctions);
200  uint32_t used = p->writePos - p->readPos;
201  if (!p->writeable && (mode || used == 0)) return -1;
202  if (mode) used = MAX_PIPE_BUFFER_SIZE - used;
203  return used;
204 }
205 
218 static struct linkedList *__pipeWait(struct object *obj, uint32_t mode, uint32_t *result)
219 {
220  struct pipe *p = objectContainer(obj, struct pipe, &pipeFunctions);
221  uint32_t used = p->writePos - p->readPos;
222 
223  if (mode)
224  {
225  /* not writeable anymore */
226  if (!p->writeable)
227  {
228  *result = -1;
229  return NULL;
230  }
231 
232  /* writeable, but the whole buffer is used -> wait */
233  if (used >= MAX_PIPE_BUFFER_SIZE)
234  return &p->writeWaiters;
235 
236  /* return number of bytes free in the buffer */
237  *result = MAX_PIPE_BUFFER_SIZE - used;
238  return NULL;
239  }
240  else
241  {
242  /* not writeable, and buffer is empty */
243  if (!p->writeable && used == 0)
244  {
245  *result = -1;
246  return NULL;
247  }
248 
249  /* buffer is empty -> wait */
250  if (used == 0)
251  return &p->readWaiters;
252 
253  /* return number of bytes used in the buffer */
254  *result = used;
255  return NULL;
256  }
257 }
258 
269 static int32_t __pipeWrite(struct object *obj, uint8_t *buf, uint32_t length)
270 {
271  struct pipe *p = objectContainer(obj, struct pipe, &pipeFunctions);
272  uint32_t used = p->writePos - p->readPos;
273 
274  /* fail if the pipe isn't writeable anymore */
275  if (!p->writeable) return -1;
276 
277  /* we expect that the buffer is still there */
278  assert(p->buffer);
279 
280  /* ensure that buffer size stays below MAX_PIPE_BUFFER_SIZE */
281  if (length > MAX_PIPE_BUFFER_SIZE - used)
282  length = MAX_PIPE_BUFFER_SIZE - used;
283 
284  if (length > p->size - p->writePos)
285  {
286 
287  /* out of space, move data to the beginning */
288  if (p->readPos != 0)
289  {
290  memmove(p->buffer, p->buffer + p->readPos, p->writePos - p->readPos);
291  p->writePos -= p->readPos;
292  p->readPos = 0;
293  }
294 
295  if (length > p->size - p->writePos)
296  {
297  uint32_t new_size = p->size * 2;
298  while (new_size < p->writePos + length) new_size *= 2;
299 
300  p->buffer = heapReAlloc(p->buffer, new_size);
301  p->size = new_size;
302  assert(p->buffer);
303  }
304  }
305 
306  if (length > 0)
307  {
308  memcpy(p->buffer + p->writePos, buf, length);
309  p->writePos += length;
310  used += length;
311  }
312 
313  /* wakeup readers if the buffer is not empty anymore */
314  if (used) queueWakeup(&p->readWaiters, true, used);
315 
316  return length;
317 }
318 
329 static int32_t __pipeRead(struct object *obj, uint8_t *buf, uint32_t length)
330 {
331  struct pipe *p = objectContainer(obj, struct pipe, &pipeFunctions);
332  uint32_t used = p->writePos - p->readPos;
333 
334  /* fail if the pipe is empty and nothing can write anymore */
335  if (!p->writeable && !used) return -1;
336 
337  /* we expect that the buffer is still there */
338  assert(p->buffer);
339 
340  /* ensure that length stays below used */
341  if (length > used) length = used;
342 
343  /* read some memory */
344  if (length > 0)
345  {
346  memcpy(buf, p->buffer + p->readPos, length);
347  p->readPos += length;
348  used -= length;
349  }
350 
351  /* buffer is now empty */
352  if (p->readPos == p->writePos)
353  {
354  if (!p->writeable)
355  {
356  heapFree(p->buffer);
357  p->buffer = NULL;
358  p->size = 0;
359  }
360 
361  p->readPos = 0;
362  p->writePos = 0;
363  }
364 
365  /* wakeup writers if the buffer is not full anymore */
366  if (used < MAX_PIPE_BUFFER_SIZE)
367  queueWakeup(&p->writeWaiters, true, p->writeable ? (MAX_PIPE_BUFFER_SIZE - used) : 0);
368 
369  return length;
370 }
371 
381 {
382  struct stdout *p;
383 
384  /* allocate some new memory */
385  if (!(p = heapAlloc(sizeof(*p))))
386  return NULL;
387 
388  /* initialize general object info */
389  __objectInit(&p->obj, &stdoutFunctions);
390 
391  return p;
392 }
393 
399 static void __stdoutDestroy(struct object *obj)
400 {
401  struct stdout *p = objectContainer(obj, struct stdout, &stdoutFunctions);
402 
403  /* release stdout memory */
404  p->obj.functions = NULL;
405  heapFree(p);
406 }
407 
414 static uint32_t __stdoutGetMinHandle(UNUSED struct object *obj)
415 {
416  /* pipe numbers can start from zero */
417  return 0;
418 }
419 
428 static int32_t __stdoutWrite(UNUSED struct object *obj, uint8_t *buf, uint32_t length)
429 {
430  consoleWriteStringLen((char *)buf, length);
431  return length;
432 }
433 
uint32_t writePos
Definition: pipe.h:49
struct linkedList writeWaiters
Definition: pipe.h:44
void * heapReAlloc(void *addr, uint32_t length)
Resizes a block of kernel memory.
Definition: allocator.c:439
const struct objectFunctions * functions
Definition: object.h:72
void * heapAlloc(uint32_t length)
Allocates a block of kernel memory.
Definition: allocator.c:363
#define assert(ex)
Definition: util.h:61
uint32_t readPos
Definition: pipe.h:50
#define UNUSED
Definition: util.h:39
bool writeable
Definition: pipe.h:52
void heapFree(void *addr)
Deallocates a block of kernel memory.
Definition: allocator.c:385
#define MAX_PIPE_BUFFER_SIZE
Definition: pipe.c:42
struct pipe * pipeCreate()
Creates a new kernel pipe object.
Definition: pipe.c:88
#define MIN_PIPE_BUFFER_SIZE
Definition: pipe.c:41
Definition: pipe.h:41
uint32_t size
Definition: pipe.h:48
void * memmove(void *destination, const void *source, size_t num)
Moves a block of memory from source to destination.
Definition: util.c:159
#define objectContainer(p, type, functions)
Definition: object.h:66
void * memcpy(void *destination, const void *source, size_t num)
Copies a block of memory from source to destination.
Definition: util.c:141
struct object obj
Definition: pipe.h:57
struct object obj
Definition: pipe.h:43
uint8_t * buffer
Definition: pipe.h:47
struct linkedList readWaiters
Definition: pipe.h:45
void consoleWriteStringLen(const char *str, size_t len)
Write a string with a fixed size to the console.
Definition: console.c:254
Definition: pipe.h:55
char mode[8]
Definition: filesystem.h:65
struct stdout * stdoutCreate()
Creates a new kernel stdout object.
Definition: pipe.c:380