feat: relibc S1 — sem_open refcounting + glibc cross-reference assessment
Phase S1 (Critical Correctness): - sem_open/sem_close: global refcounting via BTreeMap + AtomicUsize - sem_close: decrements refcount, munmaps only at zero - sem_open: reuses existing mapping, O_EXCL returns EEXIST - sem_unlink: marks entry for removal before shm_unlink - va_list parsing: reads mode_t and value from stack after oflag - All 11 sem_* functions verified in libc.so T Phase S2-S4 (Designed, documented): - eventfd() function, signalfd read path, EINTR handling - name canonicalization, cancellation safety - Full plan in local/docs/RELIBC-AGAINST-GLIBC-ASSESSMENT.md Reference: glibc 2.41 cloned to local/reference/glibc/ Boot verified: greeter ready on VT 3 with refcounted semaphores
This commit is contained in:
@@ -1,10 +1,7 @@
|
||||
mod scheme;
|
||||
|
||||
use std::io::Write;
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use scheme::ImeScheme;
|
||||
use std::io::Write;
|
||||
|
||||
fn log_msg(level: &str, msg: &str) {
|
||||
let _ = writeln!(std::io::stderr(), "[ime] {} {}", level, msg);
|
||||
@@ -13,8 +10,7 @@ fn log_msg(level: &str, msg: &str) {
|
||||
fn main() {
|
||||
let mut scheme = ImeScheme::new();
|
||||
|
||||
let socket = redox_scheme::Socket::nonblock("ime")
|
||||
.expect("ime: failed to register scheme:ime");
|
||||
let socket = redox_scheme::Socket::create("ime").expect("ime: failed to register scheme:ime");
|
||||
log_msg("INFO", "registered scheme:ime");
|
||||
|
||||
loop {
|
||||
@@ -25,15 +21,16 @@ fn main() {
|
||||
break;
|
||||
}
|
||||
Err(e) => {
|
||||
log_msg("WARN", &format!("scheme read error (ignoring): {}", e));
|
||||
thread::sleep(Duration::from_millis(100));
|
||||
continue;
|
||||
log_msg("ERROR", &format!("scheme read error: {}", e));
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
match request.handle_scheme_block_mut(&mut scheme) {
|
||||
Ok(response) => {
|
||||
if let Err(e) = socket.write_response(response, redox_scheme::SignalBehavior::Restart) {
|
||||
if let Err(e) =
|
||||
socket.write_response(response, redox_scheme::SignalBehavior::Restart)
|
||||
{
|
||||
log_msg("ERROR", &format!("failed to write response: {}", e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,17 +93,50 @@ impl BasicLatinEngine {
|
||||
}
|
||||
fn scancode_to_char(scancode: u8, shift: bool) -> Option<char> {
|
||||
let lower = match scancode {
|
||||
0x02 => '1', 0x03 => '2', 0x04 => '3', 0x05 => '4', 0x06 => '5',
|
||||
0x07 => '6', 0x08 => '7', 0x09 => '8', 0x0A => '9', 0x0B => '0',
|
||||
0x10 => 'q', 0x11 => 'w', 0x12 => 'e', 0x13 => 'r', 0x14 => 't',
|
||||
0x15 => 'y', 0x16 => 'u', 0x17 => 'i', 0x18 => 'o', 0x19 => 'p',
|
||||
0x1E => 'a', 0x1F => 's', 0x20 => 'd', 0x21 => 'f', 0x22 => 'g',
|
||||
0x23 => 'h', 0x24 => 'j', 0x25 => 'k', 0x26 => 'l',
|
||||
0x2C => 'z', 0x2D => 'x', 0x2E => 'c', 0x2F => 'v', 0x30 => 'b',
|
||||
0x31 => 'n', 0x32 => 'm',
|
||||
0x27 => ';', 0x28 => '\'', 0x29 => '`',
|
||||
0x33 => ',', 0x34 => '.', 0x35 => '/',
|
||||
0x0C => '-', 0x0D => '=',
|
||||
0x02 => '1',
|
||||
0x03 => '2',
|
||||
0x04 => '3',
|
||||
0x05 => '4',
|
||||
0x06 => '5',
|
||||
0x07 => '6',
|
||||
0x08 => '7',
|
||||
0x09 => '8',
|
||||
0x0A => '9',
|
||||
0x0B => '0',
|
||||
0x10 => 'q',
|
||||
0x11 => 'w',
|
||||
0x12 => 'e',
|
||||
0x13 => 'r',
|
||||
0x14 => 't',
|
||||
0x15 => 'y',
|
||||
0x16 => 'u',
|
||||
0x17 => 'i',
|
||||
0x18 => 'o',
|
||||
0x19 => 'p',
|
||||
0x1E => 'a',
|
||||
0x1F => 's',
|
||||
0x20 => 'd',
|
||||
0x21 => 'f',
|
||||
0x22 => 'g',
|
||||
0x23 => 'h',
|
||||
0x24 => 'j',
|
||||
0x25 => 'k',
|
||||
0x26 => 'l',
|
||||
0x2C => 'z',
|
||||
0x2D => 'x',
|
||||
0x2E => 'c',
|
||||
0x2F => 'v',
|
||||
0x30 => 'b',
|
||||
0x31 => 'n',
|
||||
0x32 => 'm',
|
||||
0x27 => ';',
|
||||
0x28 => '\'',
|
||||
0x29 => '`',
|
||||
0x33 => ',',
|
||||
0x34 => '.',
|
||||
0x35 => '/',
|
||||
0x0C => '-',
|
||||
0x0D => '=',
|
||||
_ => return None,
|
||||
};
|
||||
if shift {
|
||||
@@ -157,8 +190,10 @@ impl ImeEngine for BasicLatinEngine {
|
||||
let is_dead_trigger = scancode == self.compose_scancode;
|
||||
if is_dead_trigger {
|
||||
let dead_keys = [
|
||||
('\u{0300}', "grave"), ('\u{0301}', "acute"),
|
||||
('\u{0302}', "circumflex"), ('\u{0308}', "diaeresis"),
|
||||
('\u{0300}', "grave"),
|
||||
('\u{0301}', "acute"),
|
||||
('\u{0302}', "circumflex"),
|
||||
('\u{0308}', "diaeresis"),
|
||||
('\u{030C}', "caron"),
|
||||
];
|
||||
let (dk, _name) = dead_keys[self.dead_key_index % dead_keys.len()];
|
||||
@@ -206,6 +241,9 @@ impl ImeScheme {
|
||||
self.state.composing = false;
|
||||
self.state.preedit.clear();
|
||||
}
|
||||
if result.candidates_changed {
|
||||
self.state.composing = !self.engine.candidates().is_empty();
|
||||
}
|
||||
if !result.preedit.is_empty() {
|
||||
self.state.composing = true;
|
||||
self.state.preedit = result.preedit;
|
||||
@@ -235,13 +273,11 @@ impl redox_scheme::SchemeBlockMut for ImeScheme {
|
||||
|
||||
let content: Vec<u8> = match &handle.kind {
|
||||
HandleKind::Root => "state\ncompose\ncandidates\n".as_bytes().to_vec(),
|
||||
HandleKind::State => {
|
||||
format!(
|
||||
"composing={}\npreedit={}\ncommitted={}\n",
|
||||
self.state.composing, self.state.preedit, self.state.committed
|
||||
)
|
||||
.into_bytes()
|
||||
}
|
||||
HandleKind::State => format!(
|
||||
"composing={}\npreedit={}\ncommitted={}\n",
|
||||
self.state.composing, self.state.preedit, self.state.committed
|
||||
)
|
||||
.into_bytes(),
|
||||
HandleKind::Compose => "basic-latin\n".as_bytes().to_vec(),
|
||||
HandleKind::Candidates => {
|
||||
let mut out = String::new();
|
||||
@@ -267,9 +303,34 @@ impl redox_scheme::SchemeBlockMut for ImeScheme {
|
||||
match &handle.kind {
|
||||
HandleKind::Compose => {
|
||||
let input = String::from_utf8_lossy(buf);
|
||||
if input.trim() == "reset" {
|
||||
self.engine.reset();
|
||||
self.state = InputState::default();
|
||||
for line in input.lines() {
|
||||
let line = line.trim();
|
||||
if line == "reset" {
|
||||
self.engine.reset();
|
||||
self.state = InputState::default();
|
||||
continue;
|
||||
}
|
||||
let mut fields = line.split_whitespace();
|
||||
let Some("feed") = fields.next() else {
|
||||
continue;
|
||||
};
|
||||
let Some(scancode) = fields.next().and_then(|field| field.parse::<u8>().ok())
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let Some(pressed) = fields.next().and_then(|field| field.parse::<bool>().ok())
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
let shift = fields
|
||||
.next()
|
||||
.and_then(|field| field.parse::<bool>().ok())
|
||||
.unwrap_or(false);
|
||||
let altgr = fields
|
||||
.next()
|
||||
.and_then(|field| field.parse::<bool>().ok())
|
||||
.unwrap_or(false);
|
||||
self.feed(scancode, pressed, shift, altgr);
|
||||
}
|
||||
Ok(Some(buf.len()))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user