PatchworkOS
Loading...
Searching...
No Matches
pipe.c
Go to the documentation of this file.
1#include <kernel/ipc/pipe.h>
2
3#include <kernel/fs/file.h>
4#include <kernel/fs/vfs.h>
5#include <kernel/log/log.h>
6#include <kernel/log/panic.h>
7#include <kernel/mem/pmm.h>
9#include <kernel/sync/lock.h>
10#include <kernel/utils/ring.h>
11
12#include <assert.h>
13#include <stdlib.h>
14#include <sys/io.h>
15#include <sys/math.h>
16
19
21{
22 pipe_private_t* private = malloc(sizeof(pipe_private_t));
23 if (private == NULL)
24 {
25 return ERR;
26 }
27 private->buffer = pmm_alloc();
28 if (private->buffer == NULL)
29 {
30 free(private);
31 return ERR;
32 }
33 ring_init(&private->ring, private->buffer, PAGE_SIZE);
34 private->isReadClosed = false;
35 private->isWriteClosed = false;
36 wait_queue_init(&private->waitQueue);
37 lock_init(&private->lock);
38
39 private->readEnd = file;
40 private->writeEnd = file;
41
42 file->private = private;
43 return 0;
44}
45
47{
48 pipe_private_t* private = malloc(sizeof(pipe_private_t));
49 if (private == NULL)
50 {
51 return ERR;
52 }
53 private->buffer = pmm_alloc();
54 if (private->buffer == NULL)
55 {
56 free(private);
57 return ERR;
58 }
59 ring_init(&private->ring, private->buffer, PAGE_SIZE);
60 private->isReadClosed = false;
61 private->isWriteClosed = false;
62 wait_queue_init(&private->waitQueue);
63 lock_init(&private->lock);
64
65 private->readEnd = files[PIPE_READ];
66 private->writeEnd = files[PIPE_WRITE];
67
68 files[0]->private = private;
69 files[1]->private = private;
70 return 0;
71}
72
73static void pipe_close(file_t* file)
74{
75 pipe_private_t* private = file->private;
76 lock_acquire(&private->lock);
77 if (private->readEnd == file)
78 {
79 private->isReadClosed = true;
80 }
81 if (private->writeEnd == file)
82 {
83 private->isWriteClosed = true;
84 }
85
86 wait_unblock(&private->waitQueue, WAIT_ALL, EOK);
87 if (private->isWriteClosed && private->isReadClosed)
88 {
89 lock_release(&private->lock);
90 wait_queue_deinit(&private->waitQueue);
91 pmm_free(private->buffer);
92 free(private);
93 return;
94 }
95
96 lock_release(&private->lock);
97}
98
100{
101 if (count == 0)
102 {
103 return 0;
104 }
105
106 pipe_private_t* private = file->private;
107 if (private->readEnd != file)
108 {
109 errno = ENOTSUP;
110 return ERR;
111 }
112
113 if (count >= PAGE_SIZE)
114 {
115 errno = EINVAL;
116 return ERR;
117 }
118
119 LOCK_SCOPE(&private->lock);
120
121 if (WAIT_BLOCK_LOCK(&private->waitQueue, &private->lock,
122 ring_data_length(&private->ring) != 0 || private->isWriteClosed) == ERR)
123 {
124 return ERR;
125 }
126
127 count = MIN(count, ring_data_length(&private->ring));
128 if (ring_read(&private->ring, buffer, count) == ERR)
129 {
130 panic(NULL, "Failed to read from pipe");
131 }
132
133 wait_unblock(&private->waitQueue, WAIT_ALL, EOK);
134
135 *offset += count;
136 return count;
137}
138
140{
141 pipe_private_t* private = file->private;
142 if (private->writeEnd != file)
143 {
144 errno = ENOTSUP;
145 return ERR;
146 }
147
148 if (count >= PAGE_SIZE)
149 {
150 errno = EINVAL;
151 return ERR;
152 }
153
154 LOCK_SCOPE(&private->lock);
155
156 if (WAIT_BLOCK_LOCK(&private->waitQueue, &private->lock,
157 ring_free_length(&private->ring) >= count || private->isReadClosed) == ERR)
158 {
159 return ERR;
160 }
161
162 if (private->isReadClosed)
163 {
164 wait_unblock(&private->waitQueue, WAIT_ALL, EOK);
165 errno = EPIPE;
166 return ERR;
167 }
168
169 if (ring_write(&private->ring, buffer, count) == ERR)
170 {
171 panic(NULL, "Failed to write to pipe");
172 }
173
174 wait_unblock(&private->waitQueue, WAIT_ALL, EOK);
175
176 *offset += count;
177 return count;
178}
179
181{
182 pipe_private_t* private = file->private;
183 LOCK_SCOPE(&private->lock);
184
185 if (ring_data_length(&private->ring) != 0 || private->isWriteClosed)
186 {
187 *revents |= POLLIN;
188 }
189 if (ring_free_length(&private->ring) != 0 || private->isReadClosed)
190 {
191 *revents |= POLLOUT;
192 }
193
194 return &private->waitQueue;
195}
196
198 .open = pipe_open,
199 .open2 = pipe_open2,
200 .close = pipe_close,
201 .read = pipe_read,
202 .write = pipe_write,
203 .poll = pipe_poll,
204};
205
206void pipe_init(void)
207{
208 pipeDir = sysfs_dir_new(NULL, "pipe", NULL, NULL);
209 if (pipeDir == NULL)
210 {
211 panic(NULL, "Failed to initialize pipe directory");
212 }
213
215 if (newFile == NULL)
216 {
217 panic(NULL, "Failed to initialize pipe new file");
218 }
219}
void pipe_init(void)
Definition pipe.c:206
NORETURN void panic(const interrupt_frame_t *frame, const char *format,...)
Panic the kernel, printing a message and halting.
Definition panic.c:362
void pmm_free(void *address)
Frees a single physical page.
Definition pmm.c:211
void * pmm_alloc(void)
Allocates a single physical page.
Definition pmm.c:162
uint64_t wait_unblock(wait_queue_t *waitQueue, uint64_t amount, errno_t err)
Unblock threads waiting on a wait queue.
Definition wait.c:168
void wait_queue_init(wait_queue_t *waitQueue)
Initialize wait queue.
Definition wait.c:71
#define WAIT_ALL
Wait for all.
Definition wait.h:26
#define WAIT_BLOCK_LOCK(waitQueue, lock, condition)
Block with a spinlock.
Definition wait.h:101
void wait_queue_deinit(wait_queue_t *waitQueue)
Deinitialize wait queue.
Definition wait.c:77
static void lock_init(lock_t *lock)
Initializes a lock.
Definition lock.h:80
#define LOCK_SCOPE(lock)
Acquires a lock for the reminder of the current scope.
Definition lock.h:57
static void lock_release(lock_t *lock)
Releases a lock.
Definition lock.h:140
static void lock_acquire(lock_t *lock)
Acquires a lock, blocking until it is available.
Definition lock.h:97
static uint64_t ring_write(ring_t *ring, const void *buffer, uint64_t count)
Write data to the ring buffer.
Definition ring.h:85
static uint64_t ring_free_length(const ring_t *ring)
Get the length of free space in the ring buffer.
Definition ring.h:69
static uint64_t ring_data_length(const ring_t *ring)
Get the length of data currently stored in the ring buffer.
Definition ring.h:58
static uint64_t ring_read(ring_t *ring, void *buffer, uint64_t count)
Read data from the ring buffer.
Definition ring.h:121
static void ring_init(ring_t *ring, void *buffer, uint64_t size)
Initialize a ring buffer.
Definition ring.h:43
#define EINVAL
Invalid argument.
Definition errno.h:142
#define EPIPE
Broken pipe.
Definition errno.h:192
#define ENOTSUP
Operation not supported.
Definition errno.h:712
#define errno
Error number variable.
Definition errno.h:27
#define EOK
No error.
Definition errno.h:32
#define PIPE_READ
Pipe read end.
Definition io.h:55
#define PIPE_WRITE
Pipe write end.
Definition io.h:63
poll_events_t
Poll events type.
Definition io.h:288
@ POLLIN
File descriptor is ready to read.
Definition io.h:290
@ POLLOUT
File descriptor is ready to write.
Definition io.h:291
#define MIN(x, y)
Definition math.h:16
#define PAGE_SIZE
Memory page size.
Definition proc.h:140
#define NULL
Pointer error value.
Definition NULL.h:23
#define ERR
Integer error value.
Definition ERR.h:17
static list_t files
Definition file.c:9
static dentry_t * file
Definition log_file.c:17
EFI_PHYSICAL_ADDRESS buffer
Definition mem.c:15
static uint64_t pipe_open(file_t *file)
Definition pipe.c:20
static dentry_t * pipeDir
Definition pipe.c:17
static void pipe_close(file_t *file)
Definition pipe.c:73
static uint64_t pipe_write(file_t *file, const void *buffer, uint64_t count, uint64_t *offset)
Definition pipe.c:139
static dentry_t * newFile
Definition pipe.c:18
static uint64_t pipe_open2(file_t *files[2])
Definition pipe.c:46
static file_ops_t fileOps
Definition pipe.c:197
static uint64_t pipe_read(file_t *file, void *buffer, uint64_t count, uint64_t *offset)
Definition pipe.c:99
static wait_queue_t * pipe_poll(file_t *file, poll_events_t *revents)
Definition pipe.c:180
static atomic_long count
Definition main.c:9
__UINT64_TYPE__ uint64_t
Definition stdint.h:17
_PUBLIC void * malloc(size_t size)
Definition malloc.c:5
_PUBLIC void free(void *ptr)
Definition free.c:11
Directory entry structure.
Definition dentry.h:83
void * private
Definition dentry.h:94
File operations structure.
Definition file.h:57
uint64_t(* open)(file_t *file)
Definition file.h:58
File structure.
Definition file.h:37
Wait queue structure.
Definition wait.h:166
dentry_t * sysfs_dir_new(dentry_t *parent, const char *name, const inode_ops_t *inodeOps, void *private)
Create a new directory inside a mounted SysFS instance.
Definition sysfs.c:174
dentry_t * sysfs_file_new(dentry_t *parent, const char *name, const inode_ops_t *inodeOps, const file_ops_t *fileOps, void *private)
Create a new file inside a mounted SysFS instance.
Definition sysfs.c:216