#include <stdint.h>
+#define TIMER_HZ 100
+#define TIMER_MS_PER_TICK (1000 / TIMER_HZ) /* 10 ms */
+
void timer_init(uint32_t frequency);
uint32_t get_tick_count(void);
#include "hal/timer.h"
+#if defined(__i386__)
+#include "arch/x86/lapic.h"
+#endif
+
static uint32_t tick = 0;
uint32_t get_tick_count(void) {
}
static void hal_tick_bridge(void) {
+#if defined(__i386__)
+ if (lapic_is_enabled() && lapic_get_id() != 0) return;
+#endif
tick++;
vdso_update_tick(tick);
vga_flush();
process_wake_check(tick);
- schedule();
+ /* Preempt every SCHED_DIVISOR ticks to reduce context-switch
+ * overhead in emulated environments (QEMU TLB flush on CR3
+ * reload is expensive). Sleeping processes still wake at full
+ * TIMER_HZ resolution via process_wake_check above. */
+ if (tick % 2 == 0)
+ schedule();
}
void timer_init(uint32_t frequency) {
}
void vga_flush(void) {
+ /* Quick unlocked check: if nothing is dirty, skip entirely.
+ * All write paths (vga_write_buf, vga_put_char, vga_print) already
+ * flush immediately, so this timer-tick path is just a safety net. */
+ if (dirty_lo > dirty_hi) return;
+
uintptr_t flags = spin_lock_irqsave(&vga_lock);
vga_flush_to_hw();
spin_unlock_irqrestore(&vga_lock, flags);
vdso_init();
}
- // 8. Start Timer (Preemption!) - 50Hz
- timer_init(50);
+ // 8. Start Timer (Preemption!) - 100Hz (like Linux CONFIG_HZ=100)
+ timer_init(TIMER_HZ);
hal_cpu_enable_interrupts();
static uint32_t proc_uptime_read(fs_node_t* node, uint32_t offset, uint32_t size, uint8_t* buffer) {
(void)node;
uint32_t ticks = get_tick_count();
- uint32_t secs = (ticks * 20) / 1000;
- uint32_t frac = ((ticks * 20) % 1000) / 10;
+ uint32_t secs = (ticks * TIMER_MS_PER_TICK) / 1000;
+ uint32_t frac = ((ticks * TIMER_MS_PER_TICK) % 1000) / 10;
char tmp[64];
uint32_t len = 0;
#include "sync.h"
#include "process.h"
#include "utils.h"
+#include "timer.h"
extern uint32_t get_tick_count(void);
extern void schedule(void);
s->waiters[s->nwaiters++] = current_process;
current_process->state = PROCESS_BLOCKED;
- /* Set a wake timeout if requested (convert ms to ticks at 50 Hz) */
+ /* Set a wake timeout if requested (convert ms to ticks) */
uint32_t deadline = 0;
if (timeout_ms > 0) {
- uint32_t ticks = (timeout_ms + 19) / 20; /* round up */
+ uint32_t ticks = (timeout_ms + TIMER_MS_PER_TICK - 1) / TIMER_MS_PER_TICK;
deadline = get_tick_count() + ticks;
current_process->wake_at_tick = deadline;
current_process->state = PROCESS_SLEEPING; /* timer will wake us */
#include "elf.h"
#include "stat.h"
+#include "timer.h"
#include "vmm.h"
#include "pmm.h"
-#include "timer.h"
#include "hal/mm.h"
#include "hal/cpu.h"
#define ITIMER_REAL 0
#define ITIMER_VIRTUAL 1
#define ITIMER_PROF 2
-#define TICKS_PER_SEC 50
-#define USEC_PER_TICK (1000000U / TICKS_PER_SEC) /* 20000 */
+#define TICKS_PER_SEC TIMER_HZ
+#define USEC_PER_TICK (1000000U / TICKS_PER_SEC)
static uint32_t timeval_to_ticks(const struct k_timeval* tv) {
return tv->tv_sec * TICKS_PER_SEC + tv->tv_usec / USEC_PER_TICK;
if (req.tv_nsec >= 1000000000U) return -EINVAL;
- const uint32_t TICK_MS = 20;
uint32_t ms = req.tv_sec * 1000U + req.tv_nsec / 1000000U;
- uint32_t ticks = (ms + TICK_MS - 1) / TICK_MS;
+ uint32_t ticks = (ms + TIMER_MS_PER_TICK - 1) / TIMER_MS_PER_TICK;
if (ticks == 0 && (req.tv_sec > 0 || req.tv_nsec > 0)) ticks = 1;
if (ticks > 0) {
tp.tv_nsec = 0;
} else {
uint32_t ticks = get_tick_count();
- const uint32_t TICK_MS = 20;
- uint32_t total_ms = ticks * TICK_MS;
+ uint32_t total_ms = ticks * TIMER_MS_PER_TICK;
tp.tv_sec = total_ms / 1000U;
tp.tv_nsec = (total_ms % 1000U) * 1000000U;
}
#include "sync.h"
#include "process.h"
#include "spinlock.h"
+#include "timer.h"
#include <stddef.h>
extern void kfree(void* ptr);
extern struct process* process_create_kernel(void (*entry)(void));
-/* Return milliseconds since boot. Timer runs at 50 Hz → 20 ms per tick. */
+/* Return milliseconds since boot. */
u32_t sys_now(void) {
- return (u32_t)(get_tick_count() * 20);
+ return (u32_t)(get_tick_count() * TIMER_MS_PER_TICK);
}
/* ------------------------------------------------------------------ */
#include "process.h"
#include "net.h"
#include "e1000.h"
+#include "timer.h"
#include <stdint.h>
#include <stddef.h>
}
/* Wait for the E1000 link to stabilize in QEMU */
- process_sleep(100); /* ~2 seconds at 50 Hz */
+ process_sleep(2 * TIMER_HZ); /* ~2 seconds */
ip_addr_t target;
IP4_ADDR(&target, 10, 0, 2, 2);
process_sleep(1); /* yield for 1 tick */
}
- uint32_t dt = (get_tick_count() - t0) * 20;
+ uint32_t dt = (get_tick_count() - t0) * TIMER_MS_PER_TICK;
if (ping_got_reply) {
kprintf("[PING] reply from 10.0.2.2: seq=%d time=%dms\n",
}
if (i + 1 < PING_COUNT)
- process_sleep(50); /* ~1 second between pings */
+ process_sleep(TIMER_HZ); /* ~1 second between pings */
}
/* Cleanup in tcpip thread */