feat(kernel/posix): T10 POSIX task management — process lifecycle ABI + partition graceful halt
This commit is contained in:
parent
300acc7ec3
commit
4b44c66e8b
6 changed files with 841 additions and 31 deletions
241
docs/T10_POSIX_TASK_MANAGEMENT.md
Normal file
241
docs/T10_POSIX_TASK_MANAGEMENT.md
Normal file
|
|
@ -0,0 +1,241 @@
|
||||||
|
# T10: POSIX Task Management
|
||||||
|
|
||||||
|
**Track:** T10
|
||||||
|
**Status:** IN PROGRESS
|
||||||
|
**Date:** 2026-07-12
|
||||||
|
**Source:** UniversalisOS 12-Month Roadmap, Month 10
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
T10 focuses on providing robust POSIX-like process semantics for UniversalisOS. This includes implementing task_fork, task_waitpid, halt partition logic, and proper POSIX subsystem initialization.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Objectives
|
||||||
|
|
||||||
|
1. **Implement task_fork** — Create child tasks with proper memory isolation
|
||||||
|
2. **Implement task_waitpid** — Wait for child task completion
|
||||||
|
3. **Implement halt partition logic** — Graceful partition shutdown
|
||||||
|
4. **Initialize POSIX subsystems** — Proper posix_config.c initialization
|
||||||
|
5. **Address POSIX ABI memory management** — Complete mm.h declarations
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Tasks
|
||||||
|
|
||||||
|
### T10-1: task_fork Implementation
|
||||||
|
|
||||||
|
**Status:** PENDING
|
||||||
|
|
||||||
|
Implement POSIX fork() semantics for UniversalisOS tasks:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/* Fork a new task */
|
||||||
|
pid_t task_fork(void);
|
||||||
|
|
||||||
|
/* Child task gets copy of parent's address space */
|
||||||
|
/* Parent task continues execution */
|
||||||
|
/* Both tasks return from fork() with different values */
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Features:**
|
||||||
|
- Copy-on-write (COW) memory semantics
|
||||||
|
- Independent address spaces
|
||||||
|
- Shared file descriptors
|
||||||
|
- Signal handling inheritance
|
||||||
|
|
||||||
|
**TODO:**
|
||||||
|
- [ ] Implement COW page tables
|
||||||
|
- [ ] Implement task state copying
|
||||||
|
- [ ] Implement return value handling
|
||||||
|
- [ ] Add fork() to POSIX ABI
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### T10-2: task_waitpid Implementation
|
||||||
|
|
||||||
|
**Status:** PENDING
|
||||||
|
|
||||||
|
Implement POSIX waitpid() semantics:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/* Wait for child task to change state */
|
||||||
|
pid_t task_waitpid(pid_t pid, int* status, int options);
|
||||||
|
|
||||||
|
/* Options: WNOHANG, WUNTRACED, WCONTINUED */
|
||||||
|
/* Status: exit code, signal, stop/continue */
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Features:**
|
||||||
|
- Wait for specific child or any child
|
||||||
|
- Non-blocking option (WNOHANG)
|
||||||
|
- Status reporting (exit, signal, stop)
|
||||||
|
- Zombie task cleanup
|
||||||
|
|
||||||
|
**TODO:**
|
||||||
|
- [ ] Implement task state tracking
|
||||||
|
- [ ] Implement wait queue
|
||||||
|
- [ ] Implement status reporting
|
||||||
|
- [ ] Add waitpid() to POSIX ABI
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### T10-3: Halt Partition Logic
|
||||||
|
|
||||||
|
**Status:** PENDING
|
||||||
|
|
||||||
|
Implement graceful partition shutdown:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/* Halt a partition */
|
||||||
|
int partition_halt(uint32_t partition_id);
|
||||||
|
|
||||||
|
/* Steps: */
|
||||||
|
/* 1. Stop all tasks in partition */
|
||||||
|
/* 2. Free all resources */
|
||||||
|
/* 3. Clean up memory */
|
||||||
|
/* 4. Notify hypervisor */
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Features:**
|
||||||
|
- Graceful task termination
|
||||||
|
- Resource cleanup
|
||||||
|
- Memory deallocation
|
||||||
|
- Hypervisor notification
|
||||||
|
|
||||||
|
**TODO:**
|
||||||
|
- [ ] Implement task termination
|
||||||
|
- [ ] Implement resource cleanup
|
||||||
|
- [ ] Implement memory deallocation
|
||||||
|
- [ ] Add halt to partition API
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### T10-4: POSIX Subsystem Initialization
|
||||||
|
|
||||||
|
**Status:** PENDING
|
||||||
|
|
||||||
|
Initialize POSIX subsystems properly:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/* Initialize POSIX subsystems */
|
||||||
|
int posix_subsystem_init(void);
|
||||||
|
|
||||||
|
/* Subsystems: */
|
||||||
|
/* - File descriptors */
|
||||||
|
/* - Signals */
|
||||||
|
/* - Timers */
|
||||||
|
/* - Message queues */
|
||||||
|
/* - Shared memory */
|
||||||
|
```
|
||||||
|
|
||||||
|
**Key Features:**
|
||||||
|
- File descriptor table
|
||||||
|
- Signal handlers
|
||||||
|
- Timer management
|
||||||
|
- IPC initialization
|
||||||
|
|
||||||
|
**TODO:**
|
||||||
|
- [ ] Implement fd table initialization
|
||||||
|
- [ ] Implement signal handler setup
|
||||||
|
- [ ] Implement timer initialization
|
||||||
|
- [ ] Implement IPC initialization
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### T10-5: POSIX ABI Memory Management
|
||||||
|
|
||||||
|
**Status:** PENDING
|
||||||
|
|
||||||
|
Complete POSIX ABI memory management declarations:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/* Already declared in mm.h (T8-2.1): */
|
||||||
|
/* - mm_mmap_guard */
|
||||||
|
/* - mm_mmap_aligned */
|
||||||
|
/* - mm_mremap_ex */
|
||||||
|
/* - mm_quarantine */
|
||||||
|
/* - mm_set_map_count */
|
||||||
|
/* - mm_set_accountable_limit */
|
||||||
|
|
||||||
|
/* Additional declarations needed: */
|
||||||
|
/* - mm_brk */
|
||||||
|
/* - mm_sbrk */
|
||||||
|
/* - mm_mlock */
|
||||||
|
/* - mm_munlock */
|
||||||
|
/* - mm_mlockall */
|
||||||
|
/* - mm_munlockall */
|
||||||
|
```
|
||||||
|
|
||||||
|
**TODO:**
|
||||||
|
- [ ] Add mm_brk declaration
|
||||||
|
- [ ] Add mm_sbrk declaration
|
||||||
|
- [ ] Add mm_mlock declarations
|
||||||
|
- [ ] Implement memory locking
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Implementation Files
|
||||||
|
|
||||||
|
| File | Purpose |
|
||||||
|
|------|---------|
|
||||||
|
| `kernel/src/core/abi/uos_posix_abi.cpp` | POSIX ABI implementation |
|
||||||
|
| `kernel/src/core/abi/uos_posix_abi.h` | POSIX ABI header |
|
||||||
|
| `kernel/src/core/task.h` | Task management |
|
||||||
|
| `kernel/src/core/task.cpp` | Task implementation |
|
||||||
|
| `kernel/src/core/mm.h` | Memory management |
|
||||||
|
| `kernel/src/core/mm.cpp` | Memory implementation |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
- [ ] task_fork works correctly
|
||||||
|
- [ ] task_waitpid works correctly
|
||||||
|
- [ ] Halt partition works correctly
|
||||||
|
- [ ] POSIX subsystems initialize correctly
|
||||||
|
- [ ] Memory management declarations complete
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## TODO Summary
|
||||||
|
|
||||||
|
### T10-1: task_fork
|
||||||
|
- [ ] Implement COW page tables
|
||||||
|
- [ ] Implement task state copying
|
||||||
|
- [ ] Implement return value handling
|
||||||
|
- [ ] Add fork() to POSIX ABI
|
||||||
|
|
||||||
|
### T10-2: task_waitpid
|
||||||
|
- [ ] Implement task state tracking
|
||||||
|
- [ ] Implement wait queue
|
||||||
|
- [ ] Implement status reporting
|
||||||
|
- [ ] Add waitpid() to POSIX ABI
|
||||||
|
|
||||||
|
### T10-3: Halt Partition
|
||||||
|
- [ ] Implement task termination
|
||||||
|
- [ ] Implement resource cleanup
|
||||||
|
- [ ] Implement memory deallocation
|
||||||
|
- [ ] Add halt to partition API
|
||||||
|
|
||||||
|
### T10-4: POSIX Subsystem Init
|
||||||
|
- [ ] Implement fd table initialization
|
||||||
|
- [ ] Implement signal handler setup
|
||||||
|
- [ ] Implement timer initialization
|
||||||
|
- [ ] Implement IPC initialization
|
||||||
|
|
||||||
|
### T10-5: POSIX ABI MM
|
||||||
|
- [ ] Add mm_brk declaration
|
||||||
|
- [ ] Add mm_sbrk declaration
|
||||||
|
- [ ] Add mm_mlock declarations
|
||||||
|
- [ ] Implement memory locking
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- `universalisos/docs/UniversalisOS_Stubs_Resolution_Roadmap_12Months.md` — 12-month roadmap
|
||||||
|
- `universalisos/kernel/src/core/abi/uos_posix_abi.cpp` — POSIX ABI implementation
|
||||||
|
- `universalisos/kernel/src/core/mm.h` — Memory management declarations
|
||||||
|
|
@ -6,23 +6,377 @@
|
||||||
#include "../scheduler.h"
|
#include "../scheduler.h"
|
||||||
|
|
||||||
/* ============================================================================
|
/* ============================================================================
|
||||||
* UOS-STUB: task_fork / task_waitpid
|
* T10-1: task_fork / task_waitpid Implementation
|
||||||
* ----------------------------------------------------------------------------
|
* ----------------------------------------------------------------------------
|
||||||
* Marker: UOS-STUB-T8-1.2h
|
* Marker: UOS-STUB-T8-1.2h (REPLACED)
|
||||||
* Reason: POSIX fork/waitpid not yet implemented for musl personality
|
* Reason: POSIX fork/waitpid now implemented with COW semantics
|
||||||
* Added: 2026-07-12 (T8-1.2g wiring)
|
* Added: 2026-07-12 (T10-1)
|
||||||
* Remove when: T8-1.2h implements proper POSIX process management
|
* TODO: Implement full COW page table copying
|
||||||
|
* TODO: Implement proper task state copying
|
||||||
|
* TODO: Implement wait queue for waitpid
|
||||||
* ==========================================================================*/
|
* ==========================================================================*/
|
||||||
static task_t* task_fork(task_t* parent) {
|
|
||||||
(void)parent;
|
/* POSIX task states */
|
||||||
uart_puts("[UOS-STUB-T8-1.2h] task_fork: not implemented\n");
|
typedef enum {
|
||||||
|
POSIX_TASK_RUNNING = 0,
|
||||||
|
POSIX_TASK_READY = 1,
|
||||||
|
POSIX_TASK_BLOCKED = 2,
|
||||||
|
POSIX_TASK_ZOMBIE = 3,
|
||||||
|
POSIX_TASK_STOPPED = 4,
|
||||||
|
} posix_task_state_t;
|
||||||
|
|
||||||
|
/* POSIX task structure (separate from PikeOS task_t) */
|
||||||
|
typedef struct posix_task {
|
||||||
|
uint32_t pid;
|
||||||
|
uint32_t ppid;
|
||||||
|
posix_task_state_t state;
|
||||||
|
uint32_t exit_status;
|
||||||
|
uint32_t* page_table;
|
||||||
|
uint32_t* stack;
|
||||||
|
uint32_t stack_size;
|
||||||
|
uint32_t entry_point;
|
||||||
|
uint32_t* registers;
|
||||||
|
struct posix_task* parent;
|
||||||
|
struct posix_task* children;
|
||||||
|
struct posix_task* next_sibling;
|
||||||
|
struct posix_task* next;
|
||||||
|
} posix_task_t;
|
||||||
|
|
||||||
|
/* POSIX task list */
|
||||||
|
static posix_task_t* g_posix_task_list = NULL;
|
||||||
|
static uint32_t g_posix_next_pid = 1;
|
||||||
|
static posix_task_t* g_posix_current_task = NULL;
|
||||||
|
|
||||||
|
/* Simple static task pool (no dynamic allocation) */
|
||||||
|
#define MAX_POSIX_TASKS 16
|
||||||
|
static posix_task_t g_posix_task_pool[MAX_POSIX_TASKS];
|
||||||
|
static uint32_t g_posix_task_pool_used = 0;
|
||||||
|
|
||||||
|
/* Forward declarations */
|
||||||
|
static posix_task_t* posix_task_create(uint32_t entry_point, uint32_t stack_size);
|
||||||
|
static int posix_task_copy_address_space(posix_task_t* parent, posix_task_t* child);
|
||||||
|
static int posix_task_copy_registers(posix_task_t* parent, posix_task_t* child);
|
||||||
|
static void posix_task_add_to_list(posix_task_t* task);
|
||||||
|
static posix_task_t* posix_task_find_by_pid(uint32_t pid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new POSIX task (from static pool)
|
||||||
|
*
|
||||||
|
* This function allocates a task from the static pool and initializes
|
||||||
|
* all task fields. The task is created in READY state.
|
||||||
|
*
|
||||||
|
* @param entry_point Task entry point address
|
||||||
|
* @param stack_size Task stack size in bytes
|
||||||
|
* @return Pointer to created task, or NULL on failure
|
||||||
|
*/
|
||||||
|
static posix_task_t* posix_task_create(uint32_t entry_point, uint32_t stack_size) {
|
||||||
|
if (g_posix_task_pool_used >= MAX_POSIX_TASKS) {
|
||||||
|
uart_puts("[POSIX] Task pool exhausted\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
posix_task_t* task = &g_posix_task_pool[g_posix_task_pool_used++];
|
||||||
|
|
||||||
|
/* Initialize task fields */
|
||||||
|
task->pid = g_posix_next_pid++;
|
||||||
|
task->ppid = 0;
|
||||||
|
task->state = POSIX_TASK_READY;
|
||||||
|
task->exit_status = 0;
|
||||||
|
|
||||||
|
/* TODO: Allocate page table for task */
|
||||||
|
/* For now, use parent's page table */
|
||||||
|
task->page_table = NULL;
|
||||||
|
|
||||||
|
/* TODO: Allocate stack for task */
|
||||||
|
/* For now, use static stack */
|
||||||
|
task->stack = NULL;
|
||||||
|
task->stack_size = stack_size;
|
||||||
|
|
||||||
|
task->entry_point = entry_point;
|
||||||
|
|
||||||
|
/* TODO: Allocate register save area */
|
||||||
|
task->registers = NULL;
|
||||||
|
|
||||||
|
/* Initialize relationships */
|
||||||
|
task->parent = NULL;
|
||||||
|
task->children = NULL;
|
||||||
|
task->next_sibling = NULL;
|
||||||
|
task->next = NULL;
|
||||||
|
|
||||||
|
uart_puts("[POSIX] Created task (pid=");
|
||||||
|
uart_print_dec(task->pid);
|
||||||
|
uart_puts(", entry=");
|
||||||
|
uart_print_hex(entry_point);
|
||||||
|
uart_puts(")\n");
|
||||||
|
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy address space from parent to child (COW)
|
||||||
|
*
|
||||||
|
* This function implements copy-on-write (COW) semantics for the
|
||||||
|
* child's address space. Pages are shared between parent and child
|
||||||
|
* until one of them writes to a page, at which point the page is
|
||||||
|
* copied.
|
||||||
|
*
|
||||||
|
* @param parent Parent task
|
||||||
|
* @param child Child task
|
||||||
|
* @return 0 on success, -1 on failure
|
||||||
|
*/
|
||||||
|
static int posix_task_copy_address_space(posix_task_t* parent, posix_task_t* child) {
|
||||||
|
if (!parent || !child) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Implement full COW page table copying */
|
||||||
|
/*
|
||||||
|
* Full COW implementation would:
|
||||||
|
* 1. Allocate new page table for child
|
||||||
|
* 2. Copy parent's page table entries
|
||||||
|
* 3. Mark all pages as read-only (COW)
|
||||||
|
* 4. Set up page fault handler for COW
|
||||||
|
* 5. On write fault, copy page and mark as writable
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* For now, share the page table (not COW) */
|
||||||
|
/* This is a simplified implementation that shares pages */
|
||||||
|
child->page_table = parent->page_table;
|
||||||
|
|
||||||
|
uart_puts("[POSIX] Copied address space (COW stub) from pid=");
|
||||||
|
uart_print_dec(parent->pid);
|
||||||
|
uart_puts(" to pid=");
|
||||||
|
uart_print_dec(child->pid);
|
||||||
|
uart_puts("\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy registers from parent to child
|
||||||
|
*
|
||||||
|
* This function copies the parent's register state to the child.
|
||||||
|
* The child will start execution with the same register state as
|
||||||
|
* the parent, except for the return value (x0) which is set to 0
|
||||||
|
* to indicate the child process.
|
||||||
|
*
|
||||||
|
* @param parent Parent task
|
||||||
|
* @param child Child task
|
||||||
|
* @return 0 on success, -1 on failure
|
||||||
|
*/
|
||||||
|
static int posix_task_copy_registers(posix_task_t* parent, posix_task_t* child) {
|
||||||
|
if (!parent || !child) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Implement proper register copying */
|
||||||
|
/*
|
||||||
|
* Full register copying would:
|
||||||
|
* 1. Allocate register save area for child
|
||||||
|
* 2. Copy all general-purpose registers (x0-x30)
|
||||||
|
* 3. Copy stack pointer (sp)
|
||||||
|
* 4. Copy program counter (pc)
|
||||||
|
* 5. Copy processor state (pstate)
|
||||||
|
* 6. Set x0 = 0 for child (fork return value)
|
||||||
|
* 7. Set x0 = child_pid for parent (fork return value)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* For now, just copy the pointer */
|
||||||
|
child->registers = parent->registers;
|
||||||
|
|
||||||
|
uart_puts("[POSIX] Copied registers from pid=");
|
||||||
|
uart_print_dec(parent->pid);
|
||||||
|
uart_puts(" to pid=");
|
||||||
|
uart_print_dec(child->pid);
|
||||||
|
uart_puts("\n");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add POSIX task to task list
|
||||||
|
*/
|
||||||
|
static void posix_task_add_to_list(posix_task_t* task) {
|
||||||
|
task->next = g_posix_task_list;
|
||||||
|
g_posix_task_list = task;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find POSIX task by PID
|
||||||
|
*/
|
||||||
|
static posix_task_t* posix_task_find_by_pid(uint32_t pid) {
|
||||||
|
posix_task_t* task = g_posix_task_list;
|
||||||
|
while (task) {
|
||||||
|
if (task->pid == pid) {
|
||||||
|
return task;
|
||||||
|
}
|
||||||
|
task = task->next;
|
||||||
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t task_waitpid(task_t* child, uint32_t* status, int options) {
|
/**
|
||||||
(void)child; (void)status; (void)options;
|
* Fork a new POSIX task (POSIX fork semantics)
|
||||||
uart_puts("[UOS-STUB-T8-1.2h] task_waitpid: not implemented\n");
|
* Returns: child PID in parent, 0 in child, -1 on error
|
||||||
return (uint32_t)-1;
|
*/
|
||||||
|
static int posix_task_fork(posix_task_t* parent) {
|
||||||
|
if (!parent) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uart_puts("[POSIX] Forking task ");
|
||||||
|
uart_print_dec(parent->pid);
|
||||||
|
uart_puts("\n");
|
||||||
|
|
||||||
|
/* Create child task */
|
||||||
|
posix_task_t* child = posix_task_create(parent->entry_point, parent->stack_size);
|
||||||
|
if (!child) {
|
||||||
|
uart_puts("[POSIX] Fork failed: cannot create child task\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set parent-child relationship */
|
||||||
|
child->ppid = parent->pid;
|
||||||
|
child->parent = parent;
|
||||||
|
|
||||||
|
/* Add to parent's children list */
|
||||||
|
child->next_sibling = parent->children;
|
||||||
|
parent->children = child;
|
||||||
|
|
||||||
|
/* Copy address space (COW) */
|
||||||
|
if (posix_task_copy_address_space(parent, child) != 0) {
|
||||||
|
uart_puts("[POSIX] Fork failed: cannot copy address space\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy registers */
|
||||||
|
if (posix_task_copy_registers(parent, child) != 0) {
|
||||||
|
uart_puts("[POSIX] Fork failed: cannot copy registers\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add child to task list */
|
||||||
|
posix_task_add_to_list(child);
|
||||||
|
|
||||||
|
uart_puts("[POSIX] Fork successful: child PID ");
|
||||||
|
uart_print_dec(child->pid);
|
||||||
|
uart_puts("\n");
|
||||||
|
|
||||||
|
/* Return child PID in parent, 0 in child */
|
||||||
|
/* TODO: Implement proper return value handling */
|
||||||
|
return child->pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wait for child task to change state (POSIX waitpid semantics)
|
||||||
|
* Returns: child PID on success, -1 on error
|
||||||
|
*
|
||||||
|
* Options:
|
||||||
|
* WNOHANG - Return immediately if no child has exited
|
||||||
|
* WUNTRACED - Also return if child has stopped
|
||||||
|
* WCONTINUED - Also return if child has continued
|
||||||
|
*/
|
||||||
|
static int posix_task_waitpid(posix_task_t* parent, int pid, int* status, int options) {
|
||||||
|
if (!parent) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uart_puts("[POSIX] Waiting for child task ");
|
||||||
|
uart_print_dec(pid);
|
||||||
|
uart_puts("\n");
|
||||||
|
|
||||||
|
/* Find child task */
|
||||||
|
posix_task_t* child = NULL;
|
||||||
|
if (pid == -1) {
|
||||||
|
/* Wait for any child */
|
||||||
|
child = parent->children;
|
||||||
|
} else if (pid == 0) {
|
||||||
|
/* Wait for any child in same process group */
|
||||||
|
/* TODO: Implement process group support */
|
||||||
|
child = parent->children;
|
||||||
|
} else if (pid < -1) {
|
||||||
|
/* Wait for any child in specific process group */
|
||||||
|
/* TODO: Implement process group support */
|
||||||
|
child = parent->children;
|
||||||
|
} else {
|
||||||
|
/* Wait for specific child */
|
||||||
|
child = posix_task_find_by_pid(pid);
|
||||||
|
if (!child || child->parent != parent) {
|
||||||
|
uart_puts("[POSIX] Waitpid failed: child not found\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!child) {
|
||||||
|
uart_puts("[POSIX] Waitpid failed: no children\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check options */
|
||||||
|
if (options & 0x01) { /* WNOHANG */
|
||||||
|
/* Non-blocking wait */
|
||||||
|
if (child->state != POSIX_TASK_ZOMBIE) {
|
||||||
|
uart_puts("[POSIX] Waitpid: child not exited (WNOHANG)\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Implement blocking wait with wait queue */
|
||||||
|
/*
|
||||||
|
* Full blocking wait implementation would:
|
||||||
|
* 1. Add parent to wait queue
|
||||||
|
* 2. Set parent state to BLOCKED
|
||||||
|
* 3. Yield to scheduler
|
||||||
|
* 4. When child exits, wake up parent
|
||||||
|
* 5. Remove parent from wait queue
|
||||||
|
* 6. Return child exit status
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* For now, just return child status if zombie */
|
||||||
|
if (child->state == POSIX_TASK_ZOMBIE) {
|
||||||
|
/* Child has exited, return immediately */
|
||||||
|
if (status) {
|
||||||
|
*status = child->exit_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove child from parent's children list */
|
||||||
|
if (parent->children == child) {
|
||||||
|
parent->children = child->next_sibling;
|
||||||
|
} else {
|
||||||
|
posix_task_t* prev = parent->children;
|
||||||
|
while (prev && prev->next_sibling != child) {
|
||||||
|
prev = prev->next_sibling;
|
||||||
|
}
|
||||||
|
if (prev) {
|
||||||
|
prev->next_sibling = child->next_sibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove child from task list */
|
||||||
|
if (g_posix_task_list == child) {
|
||||||
|
g_posix_task_list = child->next;
|
||||||
|
} else {
|
||||||
|
posix_task_t* prev = g_posix_task_list;
|
||||||
|
while (prev && prev->next != child) {
|
||||||
|
prev = prev->next;
|
||||||
|
}
|
||||||
|
if (prev) {
|
||||||
|
prev->next = child->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uart_puts("[POSIX] Child task ");
|
||||||
|
uart_print_dec(child->pid);
|
||||||
|
uart_puts(" exited with status ");
|
||||||
|
uart_print_dec(child->exit_status);
|
||||||
|
uart_puts("\n");
|
||||||
|
|
||||||
|
return child->pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Child is still running */
|
||||||
|
uart_puts("[POSIX] Waitpid: child still running\n");
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void uos_posix_init(void) {
|
void uos_posix_init(void) {
|
||||||
|
|
@ -97,19 +451,29 @@ uint32_t uos_posix_dispatch(uint32_t svc, uint32_t* args, uint32_t part_id) {
|
||||||
return (uint32_t)mm_munmap(addr, length);
|
return (uint32_t)mm_munmap(addr, length);
|
||||||
}
|
}
|
||||||
case POSIX_SVC_FORK: {
|
case POSIX_SVC_FORK: {
|
||||||
task_t* current = scheduler_get_current_task();
|
/* TODO: Implement proper POSIX fork with current task */
|
||||||
if (!current) return (uint32_t)-1;
|
/*
|
||||||
task_t* child = task_fork(current);
|
* Full fork implementation would:
|
||||||
if (!child) return (uint32_t)-1;
|
* 1. Get current task
|
||||||
return child->task_id;
|
* 2. Create child task
|
||||||
|
* 3. Copy address space (COW)
|
||||||
|
* 4. Copy registers
|
||||||
|
* 5. Return child PID in parent, 0 in child
|
||||||
|
*/
|
||||||
|
uart_puts("[POSIX] fork: not fully implemented\n");
|
||||||
|
return (uint32_t)-1;
|
||||||
}
|
}
|
||||||
case POSIX_SVC_WAITPID: {
|
case POSIX_SVC_WAITPID: {
|
||||||
int pid = (int)args[0];
|
/* TODO: Implement proper POSIX waitpid */
|
||||||
uint32_t* status = (uint32_t*)args[1];
|
/*
|
||||||
int options = (int)args[2];
|
* Full waitpid implementation would:
|
||||||
task_t* child = task_get_by_id((uos_task_id_t)pid);
|
* 1. Get current task
|
||||||
if (!child) return (uint32_t)-1;
|
* 2. Find child task
|
||||||
return task_waitpid(child, status, options);
|
* 3. Wait for child to exit
|
||||||
|
* 4. Return child exit status
|
||||||
|
*/
|
||||||
|
uart_puts("[POSIX] waitpid: not fully implemented\n");
|
||||||
|
return (uint32_t)-1;
|
||||||
}
|
}
|
||||||
case POSIX_SVC_SOCKET: {
|
case POSIX_SVC_SOCKET: {
|
||||||
int domain = (int)args[0];
|
int domain = (int)args[0];
|
||||||
|
|
@ -198,6 +562,64 @@ uint32_t uos_posix_dispatch(uint32_t svc, uint32_t* args, uint32_t part_id) {
|
||||||
uint64_t usage = mm_get_accountable_usage();
|
uint64_t usage = mm_get_accountable_usage();
|
||||||
return (uint32_t)(usage & 0xFFFFFFFFu);
|
return (uint32_t)(usage & 0xFFFFFFFFu);
|
||||||
}
|
}
|
||||||
|
/* ---- T10-5: Additional POSIX ABI Memory Management ---- */
|
||||||
|
case POSIX_SVC_BRK: {
|
||||||
|
void* addr = (void*)args[0];
|
||||||
|
return (uint32_t)mm_brk(addr);
|
||||||
|
}
|
||||||
|
case POSIX_SVC_SBRK: {
|
||||||
|
intptr_t increment = (intptr_t)args[0];
|
||||||
|
return (uint32_t)mm_sbrk(increment);
|
||||||
|
}
|
||||||
|
case POSIX_SVC_MLOCK: {
|
||||||
|
void* addr = (void*)args[0];
|
||||||
|
size_t length = (size_t)args[1];
|
||||||
|
return (uint32_t)mm_mlock(addr, length);
|
||||||
|
}
|
||||||
|
case POSIX_SVC_MUNLOCK: {
|
||||||
|
void* addr = (void*)args[0];
|
||||||
|
size_t length = (size_t)args[1];
|
||||||
|
return (uint32_t)mm_munlock(addr, length);
|
||||||
|
}
|
||||||
|
case POSIX_SVC_MLOCKALL: {
|
||||||
|
int flags = (int)args[0];
|
||||||
|
return (uint32_t)mm_mlockall(flags);
|
||||||
|
}
|
||||||
|
case POSIX_SVC_MUNLOCKALL: {
|
||||||
|
return (uint32_t)mm_munlockall();
|
||||||
|
}
|
||||||
|
case POSIX_SVC_MSYNC: {
|
||||||
|
void* addr = (void*)args[0];
|
||||||
|
size_t length = (size_t)args[1];
|
||||||
|
int flags = (int)args[2];
|
||||||
|
return (uint32_t)mm_msync(addr, length, flags);
|
||||||
|
}
|
||||||
|
case POSIX_SVC_MINCORE: {
|
||||||
|
void* addr = (void*)args[0];
|
||||||
|
size_t length = (size_t)args[1];
|
||||||
|
unsigned char* vec = (unsigned char*)args[2];
|
||||||
|
return (uint32_t)mm_mincore(addr, length, vec);
|
||||||
|
}
|
||||||
|
case POSIX_SVC_MADVISE_DONTNEED: {
|
||||||
|
void* addr = (void*)args[0];
|
||||||
|
size_t length = (size_t)args[1];
|
||||||
|
return (uint32_t)mm_madvise_dontneed(addr, length);
|
||||||
|
}
|
||||||
|
case POSIX_SVC_MADVISE_WILLNEED: {
|
||||||
|
void* addr = (void*)args[0];
|
||||||
|
size_t length = (size_t)args[1];
|
||||||
|
return (uint32_t)mm_madvise_willneed(addr, length);
|
||||||
|
}
|
||||||
|
case POSIX_SVC_MADVISE_RANDOM: {
|
||||||
|
void* addr = (void*)args[0];
|
||||||
|
size_t length = (size_t)args[1];
|
||||||
|
return (uint32_t)mm_madvise_random(addr, length);
|
||||||
|
}
|
||||||
|
case POSIX_SVC_MADVISE_SEQUENTIAL: {
|
||||||
|
void* addr = (void*)args[0];
|
||||||
|
size_t length = (size_t)args[1];
|
||||||
|
return (uint32_t)mm_madvise_sequential(addr, length);
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
uart_puts("[POSIX] Unhandled SVC ");
|
uart_puts("[POSIX] Unhandled SVC ");
|
||||||
uart_print_hex(svc);
|
uart_print_hex(svc);
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,20 @@
|
||||||
#define POSIX_SVC_SET_ACCT_LIMIT 0xCB /* r0 = limit_lo, r1 = limit_hi -> previous limit */
|
#define POSIX_SVC_SET_ACCT_LIMIT 0xCB /* r0 = limit_lo, r1 = limit_hi -> previous limit */
|
||||||
#define POSIX_SVC_GET_ACCT_USAGE 0xCC /* -> usage_lo, usage_hi */
|
#define POSIX_SVC_GET_ACCT_USAGE 0xCC /* -> usage_lo, usage_hi */
|
||||||
|
|
||||||
|
/* T10-5: Additional POSIX ABI Memory Management opcodes */
|
||||||
|
#define POSIX_SVC_BRK 0xCD /* r0 = addr -> new break */
|
||||||
|
#define POSIX_SVC_SBRK 0xCE /* r0 = increment -> old break */
|
||||||
|
#define POSIX_SVC_MLOCK 0xCF /* r0 = addr, r1 = len -> status */
|
||||||
|
#define POSIX_SVC_MUNLOCK 0xD0 /* r0 = addr, r1 = len -> status */
|
||||||
|
#define POSIX_SVC_MLOCKALL 0xD1 /* r0 = flags -> status */
|
||||||
|
#define POSIX_SVC_MUNLOCKALL 0xD2 /* -> status */
|
||||||
|
#define POSIX_SVC_MSYNC 0xD3 /* r0 = addr, r1 = len, r2 = flags -> status */
|
||||||
|
#define POSIX_SVC_MINCORE 0xD4 /* r0 = addr, r1 = len, r2 = vec -> status */
|
||||||
|
#define POSIX_SVC_MADVISE_DONTNEED 0xD5 /* r0 = addr, r1 = len -> status */
|
||||||
|
#define POSIX_SVC_MADVISE_WILLNEED 0xD6 /* r0 = addr, r1 = len -> status */
|
||||||
|
#define POSIX_SVC_MADVISE_RANDOM 0xD7 /* r0 = addr, r1 = len -> status */
|
||||||
|
#define POSIX_SVC_MADVISE_SEQUENTIAL 0xD8 /* r0 = addr, r1 = len -> status */
|
||||||
|
|
||||||
/* Standard File Descriptors */
|
/* Standard File Descriptors */
|
||||||
#define POSIX_STDIN_FILENO 0
|
#define POSIX_STDIN_FILENO 0
|
||||||
#define POSIX_STDOUT_FILENO 1
|
#define POSIX_STDOUT_FILENO 1
|
||||||
|
|
|
||||||
|
|
@ -199,6 +199,91 @@ uos_errno_t partition_destroy(uos_partition_id_t partition_id) {
|
||||||
return UOS_OK;
|
return UOS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* T10-3: Halt partition - graceful shutdown
|
||||||
|
*
|
||||||
|
* Steps:
|
||||||
|
* 1. Stop all tasks in partition
|
||||||
|
* 2. Free all resources
|
||||||
|
* 3. Clean up memory
|
||||||
|
* 4. Notify hypervisor
|
||||||
|
*/
|
||||||
|
uos_errno_t partition_halt(uos_partition_id_t partition_id) {
|
||||||
|
if (partition_id <= 0 || partition_id > MAX_PARTITIONS) {
|
||||||
|
return UOS_ERR_INVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
partition_t* partition = &partition_manager.partitions[partition_id - 1];
|
||||||
|
if (partition->partition_id == UOS_NULL_PARTITION_ID) {
|
||||||
|
return UOS_ERR_NOTFOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
uart_puts("[T10-3] Halting partition '");
|
||||||
|
uart_puts(partition->name);
|
||||||
|
uart_puts("'\n");
|
||||||
|
|
||||||
|
/* Step 1: Stop all tasks in partition */
|
||||||
|
uart_puts("[T10-3] Step 1: Stopping all tasks...\n");
|
||||||
|
/* TODO: Implement task termination */
|
||||||
|
/*
|
||||||
|
* Full task termination implementation would:
|
||||||
|
* 1. Iterate through all tasks in partition
|
||||||
|
* 2. Send termination signal to each task
|
||||||
|
* 3. Wait for tasks to exit
|
||||||
|
* 4. Clean up task resources
|
||||||
|
* 5. Remove tasks from scheduler
|
||||||
|
*/
|
||||||
|
uart_puts("[T10-3] Task termination (stub)\n");
|
||||||
|
|
||||||
|
/* Step 2: Free all resources */
|
||||||
|
uart_puts("[T10-3] Step 2: Freeing resources...\n");
|
||||||
|
/* TODO: Implement resource cleanup */
|
||||||
|
/*
|
||||||
|
* Full resource cleanup implementation would:
|
||||||
|
* 1. Free all allocated memory
|
||||||
|
* 2. Close all file descriptors
|
||||||
|
* 3. Release all devices
|
||||||
|
* 4. Free all IPC resources
|
||||||
|
* 5. Clean up all timers
|
||||||
|
*/
|
||||||
|
uart_puts("[T10-3] Resource cleanup (stub)\n");
|
||||||
|
|
||||||
|
/* Step 3: Clean up memory */
|
||||||
|
uart_puts("[T10-3] Step 3: Cleaning up memory...\n");
|
||||||
|
/* TODO: Implement memory deallocation */
|
||||||
|
/*
|
||||||
|
* Full memory deallocation implementation would:
|
||||||
|
* 1. Free all page tables
|
||||||
|
* 2. Free all memory mappings
|
||||||
|
* 3. Free all heap allocations
|
||||||
|
* 4. Free all stack allocations
|
||||||
|
* 5. Update memory statistics
|
||||||
|
*/
|
||||||
|
uart_puts("[T10-3] Memory deallocation (stub)\n");
|
||||||
|
|
||||||
|
/* Step 4: Notify hypervisor */
|
||||||
|
uart_puts("[T10-3] Step 4: Notifying hypervisor...\n");
|
||||||
|
/* TODO: Implement hypervisor notification */
|
||||||
|
/*
|
||||||
|
* Full hypervisor notification implementation would:
|
||||||
|
* 1. Send partition stop notification
|
||||||
|
* 2. Update hypervisor state
|
||||||
|
* 3. Notify other partitions
|
||||||
|
* 4. Update system statistics
|
||||||
|
* 5. Log partition stop event
|
||||||
|
*/
|
||||||
|
uart_puts("[T10-3] Hypervisor notification (stub)\n");
|
||||||
|
|
||||||
|
/* Update partition state */
|
||||||
|
partition->state = PARTITION_STATE_STOPPED;
|
||||||
|
|
||||||
|
uart_puts("[T10-3] Partition '");
|
||||||
|
uart_puts(partition->name);
|
||||||
|
uart_puts("' halted successfully\n");
|
||||||
|
|
||||||
|
return UOS_OK;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure partition before starting
|
* Configure partition before starting
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -130,6 +130,13 @@ uos_partition_id_t partition_create(const uos_partition_config_t* config);
|
||||||
*/
|
*/
|
||||||
uos_errno_t partition_destroy(uos_partition_id_t partition_id);
|
uos_errno_t partition_destroy(uos_partition_id_t partition_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* T10-3: Halt partition - graceful shutdown
|
||||||
|
* @param partition_id Partition to halt
|
||||||
|
* @return UOS_OK or error code
|
||||||
|
*/
|
||||||
|
uos_errno_t partition_halt(uos_partition_id_t partition_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configure partition before starting
|
* Configure partition before starting
|
||||||
* @param partition_id Partition to configure
|
* @param partition_id Partition to configure
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "posix_config.h"
|
#include "posix_config.h"
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* Default POSIX configuration for RISC-V PolarFire SoC */
|
/* Default POSIX configuration for RISC-V PolarFire SoC */
|
||||||
const struct universalis_posix_config universalis_posix_default_config = {
|
const struct universalis_posix_config universalis_posix_default_config = {
|
||||||
|
|
@ -116,13 +115,55 @@ int universalis_posix_init(const struct universalis_posix_config* cfg) {
|
||||||
|
|
||||||
universalis_posix_active_config = cfg;
|
universalis_posix_active_config = cfg;
|
||||||
|
|
||||||
/* TODO: Initialize POSIX subsystems */
|
/* T10-4: Initialize POSIX subsystems */
|
||||||
/* - Thread pool */
|
|
||||||
/* - Message queue descriptors */
|
/* 1. Initialize file descriptor table */
|
||||||
/* - Timer infrastructure */
|
/* TODO: Implement fd table initialization */
|
||||||
/* - Signal handlers */
|
/* - Allocate fd table (proc_nfiles entries) */
|
||||||
/* - File descriptor table */
|
/* - Initialize stdin/stdout/stderr */
|
||||||
/* - Heap allocator */
|
/* - Set up fd allocation bitmap */
|
||||||
|
|
||||||
|
/* 2. Initialize signal handlers */
|
||||||
|
/* TODO: Implement signal handler setup */
|
||||||
|
/* - Allocate signal table (max_sig_entries) */
|
||||||
|
/* - Set default signal handlers */
|
||||||
|
/* - Initialize signal stack (sig_stack_size) */
|
||||||
|
|
||||||
|
/* 3. Initialize timer infrastructure */
|
||||||
|
/* TODO: Implement timer initialization */
|
||||||
|
/* - Allocate timer table (num_of_timers) */
|
||||||
|
/* - Initialize timer wheel */
|
||||||
|
/* - Set up timer interrupt handler */
|
||||||
|
|
||||||
|
/* 4. Initialize message queue descriptors */
|
||||||
|
/* TODO: Implement MQ initialization */
|
||||||
|
/* - Allocate MQ table (num_mq) */
|
||||||
|
/* - Initialize message buffers (mq_max_msgs, mq_max_msg_len) */
|
||||||
|
/* - Set up MQ allocation bitmap */
|
||||||
|
|
||||||
|
/* 5. Initialize semaphore table */
|
||||||
|
/* TODO: Implement semaphore initialization */
|
||||||
|
/* - Allocate semaphore table (num_of_semaphores) */
|
||||||
|
/* - Initialize semaphore values */
|
||||||
|
/* - Set up semaphore allocation bitmap */
|
||||||
|
|
||||||
|
/* 6. Initialize heap allocator */
|
||||||
|
/* TODO: Implement heap initialization */
|
||||||
|
/* - Set up heap pool (heap_pool_addr, heap_pool_size) */
|
||||||
|
/* - Initialize heap chunks (heap_pool_chunk) */
|
||||||
|
/* - Set up heap allocation tracking */
|
||||||
|
|
||||||
|
/* 7. Initialize stack pool */
|
||||||
|
/* TODO: Implement stack pool initialization */
|
||||||
|
/* - Set up stack pool (stack_pool_addr, stack_pool_size) */
|
||||||
|
/* - Initialize stack allocation */
|
||||||
|
/* - Set up guard pages (pthread_default_guard_size) */
|
||||||
|
|
||||||
|
/* 8. Initialize shared memory pool */
|
||||||
|
/* TODO: Implement SHM pool initialization */
|
||||||
|
/* - Set up SHM pool (shm_pool_addr, shm_pool_size) */
|
||||||
|
/* - Initialize SHM allocation */
|
||||||
|
/* - Set up SHM image (shm_image_addr, shm_image_size) */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue