Added pipe() syscall; Fixed some memleaks;
[ZeXOS.git] / kernel / lib / unistd / pipe.c
blobc27e03d1a9548e14445ae3ecedfb95290bdbd17f
1 /*
2 * ZeX/OS
3 * Copyright (C) 2009 Martin 'povik' Poviser (martin.povik@gmail.com)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
19 #include <system.h>
20 #include <string.h>
21 #include <fd.h>
22 #include <pipe.h>
24 pipe_t *pipe_list_start;
25 pipe_t *pipe_list_end;
27 int pipe (int fds[2])
29 pipe_t *p = ((pipe_t*) kmalloc (sizeof (pipe_t)));
31 fd_count ++;
32 fd_create (fd_count, FD_PIPE);
33 fds[0] = fd_count;
35 fd_count ++;
36 fd_create (fd_count, FD_PIPE);
37 fds[1] = fd_count;
39 if(!pipe_list_start) {
40 pipe_list_end = p;
41 pipe_list_start = p;
42 p->prev = NULL;
43 p->next = NULL;
44 } else {
45 pipe_list_end->next = p;
46 p->prev = pipe_list_end;
47 pipe_list_end = p;
48 p->next = NULL;
51 p->fd_a = fds[0];
52 p->fd_b = fds[1];
54 p->buffer_list_start = ((pipe_buffer_t*) kmalloc (sizeof(pipe_buffer_t)));
55 p->buffer_list_end = p->buffer_list_start;
56 p->buffer_list_start->next = NULL;
57 p->buffer_list_start->prev = NULL;
58 p->buffer_end_len = 0;
59 p->buffer_start_pos = 0;
61 return 0;
64 pipe_t *pipe_get (int fd)
66 pipe_t *p = pipe_list_start;
68 while (true) {
69 if (p->fd_a == fd
70 || p->fd_b == fd) {
71 return p;
74 if (!p->next)
75 break;
76 else
77 p = p->next;
80 return NULL;
83 unsigned int pipe_write (pipe_t *p, BYTE* buffer, unsigned int buffer_len)
85 if ((!p) || (!buffer) || (!buffer_len) || (!p->buffer_list_start))
86 return 0;
88 { // hardcore code :)
89 unsigned int block_size = 0;
90 unsigned int buffer_pos = 0;
91 pipe_buffer_t *ptr;
92 while (buffer_pos < buffer_len) {
93 if ((buffer_len - buffer_pos) >= (PIPE_BUFFER_PART_SIZE - p->buffer_end_len)) {
94 ptr = p->buffer_list_end;
95 block_size = PIPE_BUFFER_PART_SIZE - p->buffer_end_len;
96 memcpy (*((&ptr->buffer) + p->buffer_end_len), ((buffer) + buffer_pos), block_size);
97 buffer_pos += block_size;
99 p->buffer_list_end = ((pipe_buffer_t*) kmalloc(sizeof (pipe_buffer_t)));
100 p->buffer_end_len = 0;
101 ptr->next = p->buffer_list_end;
102 p->buffer_list_end->prev = ptr;
103 } else {
104 ptr = p->buffer_list_end;
105 block_size = buffer_len - buffer_pos;
106 memcpy (((ptr->buffer) + p->buffer_end_len), ((buffer) + buffer_pos), block_size);
107 p->buffer_end_len += block_size;
108 buffer_pos += block_size;
112 return buffer_pos;
116 unsigned int pipe_read (pipe_t *p, BYTE* buffer, unsigned int buffer_max_len)
118 unsigned int buffer_pos = 0;
121 if ((!p) || (!buffer) || (!buffer_max_len) || (!p->buffer_list_start))
122 return 0;
124 while (true) { // hardcore code :)
125 while (buffer_pos < buffer_max_len) {
126 pipe_buffer_t *ptr;
127 unsigned int block_size = 0;
128 unsigned int buffer_space = buffer_max_len - buffer_pos;
130 if (p->buffer_list_start == p->buffer_list_end) {
131 unsigned int pipe_dl = p->buffer_end_len - p->buffer_start_pos;
132 block_size = (pipe_dl < buffer_space) ? (pipe_dl) : (buffer_space);
134 if(p->buffer_start_pos == p->buffer_end_len)
135 break;
136 ptr = p->buffer_list_start;
137 memcpy (((buffer) + buffer_pos), ((ptr->buffer) + p->buffer_start_pos), block_size);
138 p->buffer_start_pos += block_size;
139 buffer_pos += block_size;
140 } else if (buffer_space >= PIPE_BUFFER_PART_SIZE - p->buffer_start_pos) {
141 ptr = p->buffer_list_start;
143 block_size = PIPE_BUFFER_PART_SIZE - p->buffer_start_pos;
144 memcpy (((buffer) + buffer_pos), ((ptr->buffer) + p->buffer_start_pos), block_size);
145 buffer_pos += block_size;
147 p->buffer_start_pos = 0;
148 p->buffer_list_start = ptr->next;
149 p->buffer_list_start->prev = NULL;
150 kfree(ptr);
151 } else {
152 ptr = p->buffer_list_start;
153 memcpy (((buffer) + buffer_pos), ((ptr->buffer) + p->buffer_start_pos), buffer_space);
154 p->buffer_start_pos += buffer_space;
158 if (buffer_pos == buffer_max_len)
159 return buffer_pos;
160 else
161 schedule();
165 void pipe_remove (pipe_t *pipe)
167 if (pipe->next) {
168 pipe->next->prev = pipe->prev;
169 } else {
170 if (pipe->prev)
171 pipe_list_end = pipe->prev;
172 else
173 pipe_list_end = NULL;
176 if (pipe->prev) {
177 pipe->prev->next = pipe->next;
178 } else {
179 if (pipe->next)
180 pipe_list_start = pipe->next;
181 else
182 pipe_list_start = NULL;
186 pipe_buffer_t *tmp;
187 pipe_buffer_t *p = pipe->buffer_list_start;
189 while (p) {
190 tmp = p;
191 p = p->next;
192 kfree (tmp);
196 kfree (pipe);
199 void pipe_close (int fd)
201 pipe_t *p = pipe_list_start;
203 while (true) {
204 if (p->fd_a == fd) {
205 fd_delete (fd_get (fd));
206 p->fd_a = -1;
207 if (0 > p->fd_b)
208 pipe_remove(p);
209 return;
211 if (p->fd_b == fd) {
212 fd_delete (fd_get (fd));
213 p->fd_b = -1;
214 if (0 > p->fd_a)
215 pipe_remove(p);
216 return;
219 if (!p->next)
220 break;
221 else
222 p = p->next;
225 return;