Update markdown and tabs and stuff

This commit is contained in:
2016-10-22 17:07:50 +02:00
parent 67e817490e
commit a27daafa0a
39 changed files with 2249 additions and 2139 deletions

View File

@@ -1,7 +1,7 @@
layout: post
title: "Pipes"
subtitle: "... and keyboard."
tags: [osdev]
tags: [osdev, filesystems]
In most unix-like systems, pipes can be used to make processes
communicate with each other. To the processes the pipe looks just like
@@ -33,51 +33,52 @@ Consumer/Reader:
In code this translates to
uint32_t pipe_write(INODE ino, void *buffer, uint32_t size, uint32_t offset)
{
vfs_pipe_t *pipe = (vfs_pipe_t *)ino->data;
char *buf = (char *)buffer;
uint32_t bytes_written = 0;
while(bytes_written < size)
{
while((pipe->write_pos - pipe->read_pos) < pipe->size && bytes_written < size)
{
pipe->buffer[pipe->write_pos % pipe->size] = buf[bytes_written];
bytes_written++;
pipe->write_pos++;
}
scheduler_wake(&pipe->waiting);
if(bytes_written < size)
{
scheduler_sleep(current, &pipe->waiting);
schedule();
}
}
return bytes_written;
}
uint32_t pipe_read(INODE ino, void *buffer, uint32_t size, uint32_t offset)
{
vfs_pipe_t *pipe = (vfs_pipe_t *)ino->data;
char *buf = (char *)buffer;
uint32_t bytes_read = 0;
while(bytes_read == 0)
{
while((pipe->write_pos - pipe->read_pos) > 0 && bytes_read < size)
{
buf[bytes_read] = pipe->buffer[pipe->read_pos % pipe->size];
bytes_read++;
pipe->read_pos++;
}
scheduler_wake(&pipe->waiting);
if(bytes_read == 0)
{
scheduler_sleep(current, &pipe->waiting);
schedule();
}
}
return bytes_read;
}
:::c
uint32_t pipe_write(INODE ino, void *buffer, uint32_t size, uint32_t offset)
{
vfs_pipe_t *pipe = (vfs_pipe_t *)ino->data;
char *buf = (char *)buffer;
uint32_t bytes_written = 0;
while(bytes_written < size)
{
while((pipe->write_pos - pipe->read_pos) < pipe->size && bytes_written < size)
{
pipe->buffer[pipe->write_pos % pipe->size] = buf[bytes_written];
bytes_written++;
pipe->write_pos++;
}
scheduler_wake(&pipe->waiting);
if(bytes_written < size)
{
scheduler_sleep(current, &pipe->waiting);
schedule();
}
}
return bytes_written;
}
uint32_t pipe_read(INODE ino, void *buffer, uint32_t size, uint32_t offset)
{
vfs_pipe_t *pipe = (vfs_pipe_t *)ino->data;
char *buf = (char *)buffer;
uint32_t bytes_read = 0;
while(bytes_read == 0)
{
while((pipe->write_pos - pipe->read_pos) > 0 && bytes_read < size)
{
buf[bytes_read] = pipe->buffer[pipe->read_pos % pipe->size];
bytes_read++;
pipe->read_pos++;
}
scheduler_wake(&pipe->waiting);
if(bytes_read == 0)
{
scheduler_sleep(current, &pipe->waiting);
schedule();
}
}
return bytes_read;
}
Of course there should also be:
@@ -95,87 +96,91 @@ two separate inodes - one that can be written to and one that can be
read from. The `data` field of the `vfs_node_st` struct of the two
inodes point to the same pipe struct.
typedef struct vfs_pipe
{
char *buffer;
uint32_t size;
uint32_t read_pos;
uint32_t write_pos;
uint32_t readers;
uint32_t writers;
semaphore_t semaphore;
list_head_t waiting;
} vfs_pipe_t;
:::c
typedef struct vfs_pipe
{
char *buffer;
uint32_t size;
uint32_t read_pos;
uint32_t write_pos;
uint32_t readers;
uint32_t writers;
semaphore_t semaphore;
list_head_t waiting;
} vfs_pipe_t;
The `readers` and `writers` fields are incremented or decremented when the read or
write end respectively are opened or closed... respectively...
Creating a new pipe (somewhat simplified):
uint32_t new_pipe(uint32_t size, INODE *nodes)
{
vfs_pipe_t *pipe = calloc(1, sizeof(vfs_pipe_t));
pipe->buffer = malloc(size);
pipe->size = size;
:::c
uint32_t new_pipe(uint32_t size, INODE *nodes)
{
vfs_pipe_t *pipe = calloc(1, sizeof(vfs_pipe_t));
pipe->buffer = malloc(size);
pipe->size = size;
nodes[0] = calloc(1, sizeof(vfs_node_t));
nodes[0]->d = &pipe_driver;
nodes[0]->data = pipe;
nodes[0]->flags = PIPE_READ;
nodes[0] = calloc(1, sizeof(vfs_node_t));
nodes[0]->d = &pipe_driver;
nodes[0]->data = pipe;
nodes[0]->flags = PIPE_READ;
nodes[1] = calloc(1, sizeof(vfs_node_t));
nodes[1]->d = &pipe_driver;
nodes[1]->data = pipe;
nodes[1]->flags = PIPE_WRITE;
nodes[1] = calloc(1, sizeof(vfs_node_t));
nodes[1]->d = &pipe_driver;
nodes[1]->data = pipe;
nodes[1]->flags = PIPE_WRITE;
return 0;
}
return 0;
}
###Using pipes
When starting up the keyboard driver, a pipe is created and connected to
`stdin` - the first file descriptor - of the current process.
void keyboard_init()
{
INODE tmp[2];
new_pipe(1024, tmp);
:::c
void keyboard_init()
{
INODE tmp[2];
new_pipe(1024, tmp);
keyboard_pipe = tmp[1];
vfs_open(keyboard_pipe, O_WRONLY);
keyboard_pipe = tmp[1];
vfs_open(keyboard_pipe, O_WRONLY);
process_t *p = current->proc;
p->fd[0] = calloc(1, sizeof(file_desc_t));
fd_get(p->fd[0]);
p->fd[0]->ino = tmp[0];
p->fd[0]->flags = O_RDONLY;
vfs_open(tmp[0], O_RDONLY);
process_t *p = current->proc;
p->fd[0] = calloc(1, sizeof(file_desc_t));
fd_get(p->fd[0]);
p->fd[0]->ino = tmp[0];
p->fd[0]->flags = O_RDONLY;
vfs_open(tmp[0], O_RDONLY);
register_int_handler(IRQ2INT(IRQ_KBD), keyboard_handler);
}
register_int_handler(IRQ2INT(IRQ_KBD), keyboard_handler);
}
The keyboard handler (based off
The keyboard handler (based off
[Brandon Friesen's tutorial](http://www.osdever.net/bkerndev/Docs/keyboard.htm)
writes each decoded key to the pipe:
registers_t *keyboard_handler(registers_t *r)
{
char code[2];
[...]
while(inb(KBD_STATUS_PORT) & 0x2);
scancode = inb(KBD_DATA_PORT);
code[0] = keyboard_decode(scancode);
code[1] = '\0';
if(code[0])
{
vfs_write(keyboard_pipe, (char *)code, 1, 0);
}
[...]
}
:::c
registers_t *keyboard_handler(registers_t *r)
{
char code[2];
[...]
while(inb(KBD_STATUS_PORT) & 0x2);
scancode = inb(KBD_DATA_PORT);
code[0] = keyboard_decode(scancode);
code[1] = '\0';
if(code[0])
{
vfs_write(keyboard_pipe, (char *)code, 1, 0);
}
[...]
}
At a later stage, I'll probably make the keyboard driver in the kernel
just pass the scancodes to the pipe and have the decoding done by