+ 内存管理与按需分页(Demand Paging)
+ 键盘输入
+ 多进程
-+ 44个常见的Linux/POSIX系统调用([附录1](#appendix1))
++ 47个常见的Linux/POSIX系统调用([附录1](#appendix1))
+ 用户模式
+ 信号机制
+ PCI 3.0
2. `setxattr(2)`※
2. `fgetxattr(2)`※
2. `fsetxattr(2)`※
+2. `ioctl(2)`※
+2. `getpgid(2)`
+2. `setpgid(2)`
**LunaixOS自有**
#include <lunaix/ds/llist.h>
#include <lunaix/types.h>
+#define DEV_STRUCT_MAGIC 0x5645444c
+
#define DEV_MSKIF 0x00000003
#define DEV_IFVOL 0x0 // volumetric (block) device
struct device
{
+ uint32_t magic;
struct llist_header siblings;
struct llist_header children;
struct device* parent;
void* underlay;
int (*read)(struct device* dev, void* buf, size_t offset, size_t len);
int (*write)(struct device* dev, void* buf, size_t offset, size_t len);
+ int (*exec_cmd)(struct device* dev, uint32_t req, va_list args);
};
struct device*
size_t
fifo_read(struct fifo_buf* fbuf, void* buf, size_t count);
+void
+fifo_clear(struct fifo_buf* fbuf);
+
#endif /* __LUNAIX_FIFO_BUF_H */
int
vfs_get_dtype(int itype);
+void
+vfs_ref_dnode(struct v_dnode* dnode);
+
+void
+vfs_unref_dnode(struct v_dnode* dnode);
+
void
pcache_init(struct pcache* pcache);
--- /dev/null
+#ifndef __LUNAIX_IOCTL_H
+#define __LUNAIX_IOCTL_H
+
+#include <lunaix/syscall.h>
+
+#define IOREQ(cmd, arg_num) ((((cmd)&0xffff) << 8) | ((arg_num)&0xff))
+
+#define IOCMD(req) ((req) >> 8)
+
+#define IOARGNUM(req) ((req)&0xff)
+
+#define TIOCGPGRP IOREQ(1, 0)
+#define TIOCSPGRP IOREQ(1, 1)
+#define TIOCCLSBUF IOREQ(2, 0)
+#define TIOCFLUSH IOREQ(3, 0)
+
+__LXSYSCALL2_VARG(int, ioctl, int, fd, int, req);
+
+#endif /* __LUNAIX_IOCTL_H */
__LXSYSCALL(pid_t, getppid)
+__LXSYSCALL(pid_t, getpgid)
+
+__LXSYSCALL2(pid_t, setpgid, pid_t, pid, pid_t, pgid)
+
__LXSYSCALL1(void, _exit, int, status)
__LXSYSCALL1(unsigned int, sleep, unsigned int, seconds)
#ifndef __LUNAIX_LXCONSOLE_H
#define __LUNAIX_LXCONSOLE_H
+#define TCINTR 0x03 // ETX
+#define TCEOF 0x04 // EOT
+#define TCBS 0x08 // BS
+#define TCLF 0x0A // LF
+#define TCCR 0x0D // CR
+#define TCSTOP 0x1A // SUB
+
void
lxconsole_init();
#define __SYSCALL_fgetxattr 46
#define __SYSCALL_fsetxattr 47
+#define __SYSCALL_ioctl 48
+#define __SYSCALL_getpgid 49
+#define __SYSCALL_setpgid 50
+
#define __SYSCALL_MAX 0x100
#ifndef __ASM__
asm("\n" ::"b"(p1), "c"(p2), "d"(p3), "D"(p4)); \
___DOINT33(__SYSCALL_##name, rettype) \
}
+
+#define __LXSYSCALL2_VARG(rettype, name, t1, p1, t2, p2) \
+ static rettype name(__PARAM_MAP2(t1, p1, t2, p2), ...) \
+ { \
+ void* _last = (void*)&p2 + sizeof(void*); \
+ asm("\n" ::"b"(p1), "c"(p2), "d"(_last)); \
+ ___DOINT33(__SYSCALL_##name, rettype) \
+ }
#endif
#endif /* __LUNAIX_SYSCALL_H */
.long __lxsys_setxattr /* 45 */
.long __lxsys_fgetxattr
.long __lxsys_fsetxattr
+ .long __lxsys_ioctl
+ .long __lxsys_getpgid
+ .long __lxsys_setpgid /* 50 */
2:
.rept __SYSCALL_MAX - (2b - 1b)/4
.long 0
#include <lunaix/fctrl.h>
#include <lunaix/foptions.h>
+#include <lunaix/ioctl.h>
#include <lunaix/lunistd.h>
#include <lunaix/proc.h>
+#include <lunaix/signal.h>
#include <lunaix/status.h>
#include <klibc/string.h>
printf("Error: This is a directory\n");
break;
default:
- printf("Error: Fail to open (%d)\n", errno);
+ printf("Error: (%d)\n", errno);
break;
}
}
void
-sh_main()
+sigint_handle(int signum)
+{
+ return;
+}
+
+void
+do_cat(const char* file)
+{
+ int fd = open(file, 0);
+ if (fd < 0) {
+ sh_printerr();
+ } else {
+ int sz;
+ while ((sz = read(fd, cat_buf, 1024)) > 0) {
+ write(stdout, cat_buf, sz);
+ }
+ if (sz < 0) {
+ sh_printerr();
+ }
+ close(fd);
+ printf("\n");
+ }
+}
+
+void
+do_ls(const char* path)
+{
+ int fd = open(path, 0);
+ if (fd < 0) {
+ sh_printerr();
+ } else {
+ struct dirent ent = { .d_offset = 0 };
+ int status;
+ while ((status = readdir(fd, &ent)) == 1) {
+ if (ent.d_type == DT_DIR) {
+ printf(" \033[3m%s\033[39;49m\n", ent.d_name);
+ } else {
+ printf(" %s\n", ent.d_name);
+ }
+ }
+
+ if (status < 0)
+ sh_printerr();
+
+ close(fd);
+ }
+}
+
+void
+sh_loop()
{
char buf[512];
char *cmd, *argpart;
+ pid_t p;
+ signal(_SIGINT, sigint_handle);
- printf("\n Simple shell. Use <PG_UP> or <PG_DOWN> to scroll.\n\n");
+ // set our shell as foreground process (unistd.h:tcsetpgrp is wrapper of
+ // this)
+ // stdout (by default, unless user did smth) is the tty we are currently at
+ ioctl(stdout, TIOCSPGRP, getpgid());
while (1) {
getcwd(pwd, 512);
printf("[\033[2m%s\033[39;49m]$ ", pwd);
- size_t sz = read(stdin, buf, 512);
+ size_t sz = read(stdin, buf, 511);
if (sz < 0) {
printf("fail to read user input (%d)\n", geterrno());
return;
}
- buf[sz - 1] = '\0';
+ buf[sz] = '\0';
parse_cmdline(buf, &cmd, &argpart);
if (cmd[0] == 0) {
+ printf("\n");
goto cont;
}
if (streq(cmd, "cd")) {
if (chdir(argpart) < 0) {
sh_printerr();
}
+ goto cont;
+ } else if (streq(cmd, "clear")) {
+ ioctl(stdout, TIOCCLSBUF);
+ goto cont;
} else if (streq(cmd, "ls")) {
- int fd = open(argpart, 0);
- if (fd < 0) {
- sh_printerr();
- } else {
- struct dirent ent = { .d_offset = 0 };
- int status;
- while ((status = readdir(fd, &ent)) == 1) {
- if (ent.d_type == DT_DIR) {
- printf(" \033[3m%s\033[39;49m\n", ent.d_name);
- } else {
- printf(" %s\n", ent.d_name);
- }
- }
-
- if (status < 0)
- sh_printerr();
-
- close(fd);
+ if (!(p = fork())) {
+ do_ls(argpart);
+ _exit(0);
}
} else if (streq(cmd, "cat")) {
- int fd = open(argpart, 0);
- if (fd < 0) {
- sh_printerr();
- } else {
- int sz;
- while ((sz = read(fd, cat_buf, 1024)) > 0) {
- write(stdout, cat_buf, sz);
- }
- if (sz < 0) {
- sh_printerr();
- }
- close(fd);
- printf("\n");
+ if (!(p = fork())) {
+ do_cat(argpart);
+ _exit(0);
}
} else {
- printf("unknow command");
+ printf("unknow command\n");
+ goto cont;
}
+ setpgid(p, getpgid());
+ waitpid(p, NULL, 0);
cont:
printf("\n");
}
+}
+
+void
+sh_main()
+{
+ printf("\n Simple shell. Use <PG_UP> or <PG_DOWN> to scroll.\n\n");
+ if (!fork()) {
+ sh_loop();
+ _exit(0);
+ }
+ wait(NULL);
}
\ No newline at end of file
#include <klibc/stdio.h>
#include <lunaix/device.h>
+#include <lunaix/fs.h>
#include <lunaix/fs/twifs.h>
+#include <lunaix/ioctl.h>
#include <lunaix/mm/valloc.h>
#include <lunaix/spike.h>
+#include <lunaix/syscall.h>
static DEFINE_LLIST(root_list);
size_t strlen =
__ksprintf_internal(dev->name_val, name_fmt, DEVICE_NAME_SIZE, args);
+ dev->magic = DEV_STRUCT_MAGIC;
dev->dev_id = devid++;
dev->name = HSTR(dev->name_val, strlen);
dev->parent = parent;
}
}
return NULL;
+}
+
+__DEFINE_LXSYSCALL3(int, ioctl, int, fd, int, req, va_list, args)
+{
+ int errno;
+ struct v_fd* fd_s;
+ if ((errno = vfs_getfd(fd, &fd_s))) {
+ goto done;
+ }
+
+ struct device* dev = (struct device*)fd_s->file->inode->data;
+ if (dev->magic != DEV_STRUCT_MAGIC) {
+ errno = ENODEV;
+ goto done;
+ }
+
+ if (!dev->exec_cmd) {
+ errno = EINVAL;
+ goto done;
+ }
+
+ errno = dev->exec_cmd(dev, req, args);
+
+done:
+ return DO_STATUS_OR_RETURN(errno);
}
\ No newline at end of file
mutex_init(&buf->lock);
}
+void
+fifo_clear(struct fifo_buf* fbuf)
+{
+ mutex_lock(&fbuf->lock);
+ fbuf->rd_pos = 0;
+ fbuf->wr_pos = 0;
+ fbuf->free_len = fbuf->size;
+ mutex_unlock(&fbuf->lock);
+}
+
int
fifo_backone(struct fifo_buf* fbuf)
{
map->size_acc = 0;
map->read(map);
pos += map->size_acc;
- } while (pos < fpos && map->go_next(map));
+ } while (pos <= fpos && map->go_next(map));
- if (pos < fpos) {
+ if (pos <= fpos) {
vfree(map->buffer);
return 0;
}
vfs_close(struct v_file* file)
{
int errno = 0;
- if (!(errno = file->ops->close(file))) {
+ if (file->ref_count > 1) {
+ atomic_fetch_sub(&file->ref_count, 1);
+ } else if (!(errno = file->ops->close(file))) {
atomic_fetch_sub(&file->dnode->ref_count, 1);
file->inode->open_count--;
+
+ // Remove dead lock.
+ // This happened when process is terminated while blocking on read.
+ // In that case, the process is still holding the inode lock and it will
+ // never get released.
+ // FIXME is this a good solution?
+ /*
+ * Consider two process both open the same file both with fd=x.
+ * Process A: busy on reading x
+ * Process B: do nothing with x
+ * Assume that, after a very short time, process B get terminated while
+ * process A is still busy in it's reading business. By this design, the
+ * inode lock of this file x is get released by B rather than A. And
+ * this will cause a probable race condition on A if other process is
+ * writing to this file later after B exit.
+ *
+ * A possible solution is to add a owner identification in the lock
+ * context, so only the lock holder can do the release.
+ */
+ if (mutex_on_hold(&file->inode->lock)) {
+ unlock_inode(file->inode);
+ }
mnt_chillax(file->dnode->mnt);
pcache_commit_all(file->inode);
goto done_err;
}
- if (fd_s->file->ref_count > 1) {
- fd_s->file->ref_count--;
- } else if ((errno = vfs_close(fd_s->file))) {
+ if ((errno = vfs_close(fd_s->file))) {
goto done_err;
}
file->inode->mtime = clock_unixtime();
- __SYSCALL_INTERRUPTIBLE({
- if ((file->inode->itype & VFS_IFSEQDEV) || (fd_s->flags & FO_DIRECT)) {
- errno = file->ops->write(file->inode, buf, count, file->f_pos);
- } else {
- errno = pcache_write(file->inode, buf, count, file->f_pos);
- }
- })
+ if ((file->inode->itype & VFS_IFSEQDEV) || (fd_s->flags & FO_DIRECT)) {
+ errno = file->ops->write(file->inode, buf, count, file->f_pos);
+ } else {
+ errno = pcache_write(file->inode, buf, count, file->f_pos);
+ }
if (errno > 0) {
file->f_pos += errno;
return DO_STATUS(errno);
}
+void
+vfs_ref_dnode(struct v_dnode* dnode)
+{
+ atomic_fetch_add(&dnode->ref_count, 1);
+ mnt_mkbusy(dnode->mnt);
+}
+
+void
+vfs_unref_dnode(struct v_dnode* dnode)
+{
+ atomic_fetch_sub(&dnode->ref_count, 1);
+ mnt_chillax(dnode->mnt);
+}
+
int
-__vfs_do_chdir(struct v_dnode* dnode)
+vfs_do_chdir(struct proc_info* proc, struct v_dnode* dnode)
{
int errno = 0;
goto done;
}
- if (__current->cwd) {
- atomic_fetch_sub(&__current->cwd->ref_count, 1);
- mnt_chillax(__current->cwd->mnt);
+ if (proc->cwd) {
+ vfs_unref_dnode(proc->cwd);
}
- atomic_fetch_add(&dnode->ref_count, 1);
- mnt_mkbusy(dnode->mnt);
- __current->cwd = dnode;
+ vfs_ref_dnode(dnode);
+ proc->cwd = dnode;
unlock_dnode(dnode);
goto done;
}
- errno = __vfs_do_chdir(dnode);
+ errno = vfs_do_chdir(__current, dnode);
done:
return DO_STATUS(errno);
goto done;
}
- errno = __vfs_do_chdir(fd_s->file->dnode);
+ errno = vfs_do_chdir(__current, fd_s->file->dnode);
done:
return DO_STATUS(errno);
key = key & (0xffdf |
-('a' > key || key > 'z' || !(state & KBD_KEY_FCAPSLKED)));
- struct input_evt_pkt ipkt = {
- .pkt_type = (state & KBD_KEY_FPRESSED) ? PKT_PRESS : PKT_RELEASE,
- .scan_code = scancode,
- .sys_code = key,
- };
+ struct input_evt_pkt ipkt = { .pkt_type = (state & KBD_KEY_FPRESSED)
+ ? PKT_PRESS
+ : PKT_RELEASE,
+ .scan_code = scancode,
+ .sys_code = (state << 16) | key };
input_fire_event(kbd_idev, &ipkt);
struct proc_info* gruppenfuhrer = get_process(pgid);
- if (!gruppenfuhrer || proc->pgid == proc->pid) {
+ if (!gruppenfuhrer || proc->pgid == gruppenfuhrer->pid) {
__current->k_status = EINVAL;
return -1;
}
pcb->intr_ctx = __current->intr_ctx;
pcb->parent = __current;
+ if (__current->cwd) {
+ pcb->cwd = __current->cwd;
+ vfs_ref_dnode(pcb->cwd);
+ }
+
__copy_fdtable(pcb);
region_copy(&__current->mm.regions, &pcb->mm.regions);
sched_ctx._procs[index] = 0;
llist_delete(&proc->siblings);
+ llist_delete(&proc->grp_member);
+ llist_delete(&proc->tasks);
+ llist_delete(&proc->sleep.sleepers);
+
+ if (proc->cwd) {
+ vfs_unref_dnode(proc->cwd);
+ }
for (size_t i = 0; i < VFS_MAX_FD; i++) {
struct v_fd* fd = proc->fdtable->fds[i];
{
__SIGSET(pos->sig_pending, signum);
}
- return 0;
send_single:
if (PROC_TERMINATED(proc->state)) {
void
__read_children(struct twimap* map)
{
- struct proc_info* proc = twimap_index(map, struct proc_info*);
+ struct llist_header* proc_list = twimap_index(map, struct llist_header*);
+ struct proc_info* proc =
+ container_of(proc_list, struct proc_info, siblings);
if (!proc)
return;
twimap_printf(map, "%d ", proc->pid);
int
__next_children(struct twimap* map)
{
- struct proc_info* proc = twimap_index(map, struct proc_info*);
+ struct llist_header* proc = twimap_index(map, struct llist_header*);
+ struct proc_info* current = twimap_data(map, struct proc_info*);
if (!proc)
return 0;
- map->index = container_of(proc->siblings.next, struct proc_info, siblings);
- if (map->index == proc) {
+ map->index = proc->next;
+ if (map->index == ¤t->children) {
return 0;
}
return 1;
map->index = 0;
return;
}
- map->index = container_of(proc->children.next, struct proc_info, siblings);
+ map->index = proc->children.next;
}
void
if (!tattr || !(proc = get_process(pid)))
return ENOENT;
- int errno = taskfs_mknod(dnode, pid, taskfs_next_counter(), VFS_IFFILE);
+ int errno =
+ taskfs_mknod(dnode, pid, taskfs_next_counter(), VFS_IFSEQDEV);
if (!errno) {
tattr->map_file->data = proc;
dnode->inode->data = tattr->map_file;
#include <klibc/string.h>
#include <lunaix/device.h>
#include <lunaix/input.h>
+#include <lunaix/ioctl.h>
#include <lunaix/keyboard.h>
#include <lunaix/lxconsole.h>
#include <lunaix/mm/pmm.h>
#include <lunaix/tty/console.h>
#include <lunaix/tty/tty.h>
+#include <lunaix/lxsignal.h>
+
static struct console lx_console;
int
int
__tty_read(struct device* dev, void* buf, size_t offset, size_t len);
+void
+console_flush();
+
static waitq_t lx_reader;
-static volatile char key;
+static volatile char ttychr;
+
+static pid_t fg_pgid = 0;
+
+inline void
+print_control_code(const char cntrl)
+{
+ console_write_char('^');
+ console_write_char(cntrl + 64);
+}
int
__lxconsole_listener(struct input_device* dev)
{
- uint32_t keycode = dev->current_pkt.sys_code;
+ uint32_t key = dev->current_pkt.sys_code;
uint32_t type = dev->current_pkt.pkt_type;
- if (type == PKT_PRESS) {
- if (keycode == KEY_PG_UP) {
- console_view_up();
- } else if (keycode == KEY_PG_DOWN) {
- console_view_down();
- }
+ kbd_kstate_t state = key >> 16;
+ ttychr = key & 0xff;
+ key = key & 0xffff;
+
+ if (type == PKT_RELEASE) {
goto done;
}
- if ((keycode & 0xff00) > KEYPAD) {
+
+ if ((state & KBD_KEY_FLCTRL_HELD)) {
+ char cntrl = (char)(ttychr | 0x20);
+ if ('a' > cntrl || cntrl > 'z') {
+ goto done;
+ }
+ ttychr = cntrl - 'a' + 1;
+ switch (ttychr) {
+ case TCINTR:
+ signal_send(-fg_pgid, _SIGINT);
+ print_control_code(ttychr);
+ break;
+ case TCSTOP:
+ signal_send(-fg_pgid, _SIGSTOP);
+ print_control_code(ttychr);
+ break;
+ default:
+ break;
+ }
+ } else if (key == KEY_PG_UP) {
+ console_view_up();
+ goto done;
+ } else if (key == KEY_PG_DOWN) {
+ console_view_down();
+ goto done;
+ } else if ((key & 0xff00) <= KEYPAD) {
+ ttychr = key;
+ } else {
goto done;
}
- key = (char)(keycode & 0x00ff);
-
pwake_all(&lx_reader);
done:
return INPUT_EVT_NEXT;
}
+int
+__tty_exec_cmd(struct device* dev, uint32_t req, va_list args)
+{
+ switch (req) {
+ case TIOCGPGRP:
+ return fg_pgid;
+ case TIOCSPGRP:
+ fg_pgid = va_arg(args, pid_t);
+ break;
+ case TIOCCLSBUF:
+ fifo_clear(&lx_console.output);
+ fifo_clear(&lx_console.input);
+ lx_console.wnd_start = 0;
+ lx_console.lines = 0;
+ lx_console.output.flags |= FIFO_DIRTY;
+ break;
+ case TIOCFLUSH:
+ lx_console.output.flags |= FIFO_DIRTY;
+ console_flush();
+ break;
+ default:
+ return EINVAL;
+ }
+ return 0;
+}
+
void
lxconsole_init()
{
struct device* tty_dev = device_addseq(NULL, &lx_console, "tty");
tty_dev->write = __tty_write;
tty_dev->read = __tty_read;
+ tty_dev->exec_cmd = __tty_exec_cmd;
waitq_init(&lx_reader);
input_add_listener(__lxconsole_listener);
while (count < len) {
pwait(&lx_reader);
- if (key == 0x08) {
- if (fifo_backone(&console->input)) {
- console_write_char(key);
+ if (ttychr < 0x1B) {
+ // ASCII control codes
+ switch (ttychr) {
+ case TCINTR:
+ fifo_clear(&console->input);
+ return 0;
+ case TCBS:
+ if (fifo_backone(&console->input)) {
+ console_write_char(ttychr);
+ }
+ continue;
+ case TCLF:
+ case TCCR:
+ goto proceed;
+ default:
+ break;
}
+ print_control_code(ttychr);
continue;
}
- console_write_char(key);
- if (!fifo_putone(&console->input, key) || key == '\n') {
+
+ proceed:
+ console_write_char(ttychr);
+ if (!fifo_putone(&console->input, ttychr) || ttychr == '\n') {
break;
}
}