@hardwaretech
import React from "react"; import { Button } from "@/components/ui/button"; import { Download, FileText, CheckCircle } from "lucide-react";
export default function ARoSDocs() { const [downloading, setDownloading] = React.useState(false); const [downloaded, setDownloaded] = React.useState(false);
const handleDownload = () => { setDownloading(true);
// The complete HTML documentation const htmlContent = `
AROS Java Porting Guide - Complete Technical Documentation * { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; line-height: 1.6; color: #333; background: #f5f5f5; padding: 20px; }
.container { max-width: 900px; margin: 0 auto; background: white; padding: 40px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
.cover { text-align: center; padding: 60px 20px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; margin: -40px -40px 40px -40px; page-break-after: always; }
.cover h1 { font-size: 2.5em; margin-bottom: 20px; text-shadow: 2px 2px 4px rgba(0,0,0,0.3); }
.cover p { font-size: 1.2em; opacity: 0.9; }
h1, h2, h3 { color: #2c3e50; margin-top: 30px; margin-bottom: 15px; }
h1 { font-size: 2em; border-bottom: 3px solid #667eea; padding-bottom: 10px; }
h2 { font-size: 1.6em; color: #667eea; margin-top: 40px; }
h3 { font-size: 1.3em; color: #764ba2; }
code { background: #f8f9fa; padding: 2px 6px; border-radius: 3px; font-family: 'Courier New', monospace; font-size: 0.9em; }
pre { background: #2d2d2d; color: #f8f9fa; padding: 20px; border-radius: 5px; overflow-x: auto; margin: 20px 0; border-left: 4px solid #667eea; }
pre code { background: none; color: inherit; padding: 0; }
.info-box { background: #e3f2fd; border-left: 4px solid #2196f3; padding: 15px; margin: 20px 0; border-radius: 4px; }
.warning-box { background: #fff3e0; border-left: 4px solid #ff9800; padding: 15px; margin: 20px 0; border-radius: 4px; }
.tip-box { background: #e8f5e9; border-left: 4px solid #4caf50; padding: 15px; margin: 20px 0; border-radius: 4px; }
table { width: 100%; border-collapse: collapse; margin: 20px 0; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }
th, td { padding: 12px; text-align: left; border: 1px solid #ddd; }
th { background: #667eea; color: white; font-weight: bold; }
tr:nth-child(even) { background: #f8f9fa; }
ul, ol { margin-left: 30px; margin-bottom: 15px; }
li { margin-bottom: 8px; }
.toc { background: #f8f9fa; padding: 20px; border-radius: 8px; margin: 30px 0; }
.toc h2 { margin-top: 0; color: #2c3e50; }
.toc ul { list-style: none; margin-left: 0; }
.toc li { margin-bottom: 10px; }
.toc a { color: #667eea; text-decoration: none; font-weight: 500; }
.toc a:hover { text-decoration: underline; }
@media print { body { background: white; padding: 0; }
.container { box-shadow: none; padding: 20px; }
h1, h2 { page-break-after: avoid; }
pre, table { page-break-inside: avoid; }
.cover { margin: 0; } }
@page { margin: 2cm; }
🚀 AROS Java Porting Guide Complete Technical Documentation for JamVM on AROS Version 1.0 | ${new Date().toLocaleDateString()}
📋 Table of Contents
1. Introduction & Overview This guide documents the process of porting JamVM (a lightweight Java Virtual Machine) to the AROS operating system. AROS is an open-source operating system compatible with AmigaOS at the API level.
📌 Project Goal: Enable Java applications to run natively on AROS by implementing POSIX-compatible interfaces using AROS-specific system calls.
Architecture Overview The porting strategy involves creating compatibility layers that translate POSIX calls to AROS equivalents:
Java Application ↓ JamVM Core ↓ POSIX Interface ↓ Compatibility Layer ← YOU ARE HERE ↓ AROS System Calls ↓ AROS Kernel
Key Components to Port - Threading: POSIX threads → AROS Tasks/Processes
- Memory: malloc/mmap → AllocMem/AllocVec
- Dynamic Loading: dlopen → OpenLibrary
- Signals: POSIX signals → AROS signals
- File I/O: Standard file operations
2. Prerequisites & Setup
Required Knowledge - C programming (intermediate to advanced)
- POSIX threading concepts
- Basic understanding of virtual machines
- AROS system programming basics
- Cross-compilation experience (helpful)
Development Environment
💡 Recommended Setup: Cross-compile on Linux for AROS target to speed up development.
# Install AROS cross-compiler sudo apt-get install aros-toolchain-i386
# Clone JamVM source git clone https://github.com/jamvm/jamvm.git cd jamvm
# Create AROS porting directory mkdir -p src/os/aros
File Structure
jamvm/ ├── src/ │ ├── os/ │ │ ├── aros/ ← Your new files │ │ │ ├── os.c ← Main OS abstraction │ │ │ ├── threads.c ← Threading implementation │ │ │ └── dll.c ← Dynamic loading │ ├── jam.c │ └── ... ├── configure.ac ← Modify for AROS └── Makefile.am
3. AROS API Translation Table
Threading Functions
POSIX Function | AROS Equivalent | Notes |
|---|
pthread_create() | CreateNewProc() | Create new process/thread | pthread_join() | Wait() + Signal() | Wait for thread completion | pthread_mutex_init() | InitSemaphore() | Initialize mutex/semaphore | pthread_mutex_lock() | ObtainSemaphore() | Acquire lock | pthread_mutex_unlock() | ReleaseSemaphore() | Release lock | pthread_cond_init() | Custom implementation | Use signals + semaphores | pthread_cond_wait() | Wait() + ObtainSemaphore() | Condition variable wait | pthread_cond_signal() | Signal() | Wake one waiter |
Memory Management
POSIX Function | AROS Equivalent | Notes |
|---|
malloc() | AllocVec() | Allocate memory | free() | FreeVec() | Free memory | mmap() | AllocMem() + MEMF_PUBLIC | Memory mapping | munmap() | FreeMem() | Unmap memory |
Dynamic Loading
POSIX Function | AROS Equivalent | Notes |
|---|
dlopen() | OpenLibrary() | Load shared library | dlsym() | GetProcAddress() | Find symbol address | dlclose() | CloseLibrary() | Unload library | dlerror() | Custom error tracking | Store last error string |
4. Threading Implementation
Thread Creation Wrapper
⚠️ Important: AROS uses processes/tasks instead of traditional POSIX threads. Each "thread" is actually a separate process.
/* src/os/aros/threads.c */ #include <proto/exec.h> #include <proto/dos.h> #include <exec/memory.h>
typedef struct { void *(*start_routine)(void *); void *arg; struct Task *task; ULONG signal_bit; } AROSThread;
int pthread_create_aros(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg) { AROSThread *aros_thread = AllocVec(sizeof(AROSThread), MEMF_CLEAR); if (!aros_thread) return ENOMEM;
aros_thread->start_routine = start_routine; aros_thread->arg = arg; // Allocate signal for thread communication aros_thread->signal_bit = AllocSignal(-1); // Create new process struct TagItem tags[] = { {NP_Entry, (IPTR)thread_entry_wrapper}, {NP_Name, (IPTR)"JamVM Thread"}, {NP_Priority, 0}, {NP_StackSize, 65536}, {NP_UserData, (IPTR)aros_thread}, {TAG_DONE, 0} }; struct Process *proc = CreateNewProc(tags); if (!proc) { FreeSignal(aros_thread->signal_bit); FreeVec(aros_thread); return EAGAIN; } aros_thread->task = (struct Task *)proc; *thread = (pthread_t)aros_thread; return 0; }
static void thread_entry_wrapper(void) { struct Process *proc = (struct Process *)FindTask(NULL); AROSThread *aros_thread = (AROSThread *)proc->pr_Task.tc_UserData; // Call the actual thread function aros_thread->start_routine(aros_thread->arg); // Signal parent that we're done Signal(aros_thread->task, 1L << aros_thread->signal_bit); }
Mutex Implementation
typedef struct { struct SignalSemaphore semaphore; } AROSMutex;
int pthread_mutex_init_aros(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr) { AROSMutex *aros_mutex = AllocVec(sizeof(AROSMutex), MEMF_CLEAR); if (!aros_mutex) return ENOMEM; InitSemaphore(&aros_mutex->semaphore); *mutex = (pthread_mutex_t)aros_mutex; return 0; }
int pthread_mutex_lock_aros(pthread_mutex_t *mutex) { AROSMutex *aros_mutex = (AROSMutex *)*mutex; ObtainSemaphore(&aros_mutex->semaphore); return 0; }
int pthread_mutex_unlock_aros(pthread_mutex_t *mutex) { AROSMutex *aros_mutex = (AROSMutex *)*mutex; ReleaseSemaphore(&aros_mutex->semaphore); return 0; }
Condition Variable Implementation
💡 Tip: AROS doesn't have native condition variables, so we implement them using semaphores and signals.
typedef struct { struct SignalSemaphore semaphore; struct MinList waiters; ULONG signal_mask; } AROSCondVar;
typedef struct { struct MinNode node; struct Task *task; ULONG signal_bit; } CondWaiter;
int pthread_cond_wait_aros(pthread_cond_t *cond, pthread_mutex_t *mutex) { AROSCondVar *aros_cond = (AROSCondVar *)*cond; AROSMutex *aros_mutex = (AROSMutex *)*mutex; // Allocate waiter structure CondWaiter *waiter = AllocVec(sizeof(CondWaiter), MEMF_CLEAR); waiter->task = FindTask(NULL); waiter->signal_bit = AllocSignal(-1); // Add to waiters list ObtainSemaphore(&aros_cond->semaphore); AddTail((struct List *)&aros_cond->waiters, (struct Node *)waiter); ReleaseSemaphore(&aros_cond->semaphore); // Release mutex and wait pthread_mutex_unlock_aros(mutex); Wait(1L << waiter->signal_bit); // Reacquire mutex pthread_mutex_lock_aros(mutex); FreeSignal(waiter->signal_bit); FreeVec(waiter); return 0; }
int pthread_cond_signal_aros(pthread_cond_t *cond) { AROSCondVar *aros_cond = (AROSCondVar *)*cond; ObtainSemaphore(&aros_cond->semaphore); CondWaiter *waiter = (CondWaiter *)RemHead((struct List *)&aros_cond->waiters); if (waiter) { Signal(waiter->task, 1L << waiter->signal_bit); } ReleaseSemaphore(&aros_cond->semaphore); return 0; }
5. Dynamic Library Loading
dlopen Implementation
/* src/os/aros/dll.c */ #include <proto/exec.h> #include <dlfcn.h>
static char last_error[256] = {0};
void *dlopen_aros(const char *filename, int flag) { if (!filename) return NULL; // Try to open as AROS library struct Library *lib = OpenLibrary((CONST_STRPTR)filename, 0); if (!lib) { snprintf(last_error, sizeof(last_error), "Cannot open library: %s", filename); return NULL; } return (void *)lib; }
void *dlsym_aros(void *handle, const char *symbol) { if (!handle || !symbol) { strcpy(last_error, "Invalid handle or symbol"); return NULL; } // AROS libraries use a different symbol resolution mechanism // You may need to implement a custom symbol table lookup here // For now, return NULL and indicate unsupported strcpy(last_error, "Symbol lookup not implemented"); return NULL; }
int dlclose_aros(void *handle) { if (!handle) return -1; CloseLibrary((struct Library *)handle); return 0; }
char *dlerror_aros(void) { if (last_error[0] == '\\0') return NULL; return last_error; }
6. Memory Management
malloc/free Wrappers
/* Memory allocation wrappers for AROS */ void *malloc_aros(size_t size) { return AllocVec(size, MEMF_PUBLIC | MEMF_CLEAR); }
void free_aros(void *ptr) { if (ptr) FreeVec(ptr); }
void *calloc_aros(size_t nmemb, size_t size) { size_t total = nmemb * size; return AllocVec(total, MEMF_PUBLIC | MEMF_CLEAR); }
void *realloc_aros(void *ptr, size_t size) { if (!ptr) return malloc_aros(size); if (size == 0) { free_aros(ptr); return NULL; } // AROS doesn't have realloc, so we allocate new and copy void *new_ptr = malloc_aros(size); if (new_ptr && ptr) { // Note: This doesn't know the old size, may need tracking memcpy(new_ptr, ptr, size); free_aros(ptr); } return new_ptr; }
⚠️ Issue: The realloc implementation above doesn't know the original allocation size. Consider maintaining a size tracking table.
Memory Mapping (mmap)
void *mmap_aros(void *addr, size_t length, int prot, int flags, int fd, off_t offset) { // AROS doesn't have true mmap, use regular allocation void *mem = AllocMem(length, MEMF_PUBLIC); if (!mem) return MAP_FAILED; // If mapping a file, read it if (fd != -1) { // Read file contents into memory // This is simplified - real implementation needs DOS library } return mem; }
int munmap_aros(void *addr, size_t length) { if (!addr) return -1; FreeMem(addr, length); return 0; }
7. Signal Handling
⚠️ Challenge: AROS signals are fundamentally different from POSIX signals. Direct translation is not possible.
Signal Handling Strategy
Instead of trying to emulate POSIX signals, we can:
- Disable signal-dependent code in JamVM configuration
- Use AROS signals for basic IPC (Inter-Process Communication)
- Implement minimal signal handler for critical signals only
// Minimal signal compatibility layer typedef void (*sighandler_t)(int);
static sighandler_t signal_handlers[32] = {0};
sighandler_t signal_aros(int signum, sighandler_t handler) { if (signum < 0 || signum >= 32) return SIG_ERR; sighandler_t old_handler = signal_handlers[signum]; signal_handlers[signum] = handler; return old_handler; }
// Simplified - real implementation would need more work int raise_aros(int signum) { if (signum >= 0 && signum < 32 && signal_handlers[signum]) { signal_handlers[signum](signum); return 0; } return -1; }
💡 Recommendation: Configure JamVM with --disable-signals if possible to avoid this complexity.
8. Build System Integration
configure.ac Modifications
# Add AROS target detection case "$host_os" in aros*) AC_DEFINE([HAVE_AROS], 1, [Define if targeting AROS]) os_dir=aros ;; *) os_dir=linux ;; esac
AC_SUBST(os_dir)
# Add AROS-specific compiler flags if test "$os_dir" = "aros"; then CFLAGS="$CFLAGS -noixemul -nix" LDFLAGS="$LDFLAGS -noixemul" fi
Makefile.am Changes
# Add AROS source files if OS_AROS libos_la_SOURCES = \\ os/aros/os.c \\ os/aros/threads.c \\ os/aros/dll.c endif
# Link against AROS libraries if OS_AROS libos_la_LIBADD = -lexec -ldos endif
Cross-Compilation Script
#!/bin/bash # build-aros.sh - Cross-compile JamVM for AROS
export CC=i386-aros-gcc export CXX=i386-aros-g++ export AR=i386-aros-ar export RANLIB=i386-aros-ranlib
./configure \\ --host=i386-aros \\ --prefix=/AROS/Development/jamvm \\ --disable-signals \\ --disable-zip \\ --with-classpath-install-dir=/AROS/Development/classpath
make clean make -j$(nproc) make install
9. Testing & Validation
Unit Test Strategy
📌 Testing Approach: Start with simple tests and gradually increase complexity.
Test 1: Basic Execution
// test_hello.java public class TestHello { public static void main(String[] args) { System.out.println("Hello from AROS!"); } }
Test 2: Threading
// test_threads.java public class TestThreads { public static void main(String[] args) { Thread t1 = new Thread(() -> { for (int i = 0; i < 5; i++) { System.out.println("Thread 1: " + i); try { Thread.sleep(100); } catch (InterruptedException e) {} } }); Thread t2 = new Thread(() -> { for (int i = 0; i < 5; i++) { System.out.println("Thread 2: " + i); try { Thread.sleep(100); } catch (InterruptedException e) {} } }); t1.start(); t2.start(); try { t1.join(); t2.join(); } catch (InterruptedException e) {} System.out.println("Done!"); } }
Test 3: Memory Allocation
// test_memory.java import java.util.ArrayList;
public class TestMemory { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); for (int i = 0; i < 10000; i++) { list.add(i); } System.out.println("Allocated: " + list.size() + " integers"); // Force garbage collection System.gc(); System.out.println("GC complete"); } }
Debug Techniques
Enable Debug Output
// Add to your AROS code #define DEBUG_THREADS 1
#if DEBUG_THREADS #define DPRINTF(fmt, ...) \\ printf("[AROS-Thread] " fmt "\\n", ##__VA_ARGS__) #else #define DPRINTF(fmt, ...) #endif
// Usage DPRINTF("Creating thread with stack size: %lu", stack_size);
Memory Leak Detection
// Track allocations static long allocations = 0; static long deallocations = 0;
void *malloc_aros_debug(size_t size) { void *ptr = AllocVec(size, MEMF_PUBLIC | MEMF_CLEAR); if (ptr) allocations++; printf("ALLOC: %p (%zu bytes) [Total: %ld]\\n", ptr, size, allocations - deallocations); return ptr; }
void free_aros_debug(void *ptr) { if (ptr) { deallocations++; printf("FREE: %p [Total: %ld]\\n", ptr, allocations - deallocations); FreeVec(ptr); } }
10. Known Issues & Solutions
Issue 1: Stack Size Limitations
Problem: Default AROS stack size may be too small for JVM threads.
Solution:
// Increase stack size when creating processes struct TagItem tags[] = { {NP_Entry, (IPTR)thread_entry_wrapper}, {NP_Name, (IPTR)"JamVM Thread"}, {NP_Priority, 0}, {NP_StackSize, 131072}, // 128KB instead of default {NP_UserData, (IPTR)aros_thread}, {TAG_DONE, 0} };
Issue 2: Classpath Location
Problem: Java class libraries path differs on AROS.
Solution:
// Set CLASSPATH environment variable setenv CLASSPATH /AROS/Development/classpath/share/classpath
// Or hardcode in JamVM export JAVA_HOME=/AROS/Development/jamvm export CLASSPATH=$JAVA_HOME/share/classpath
Issue 3: Symbol Resolution in Dynamic Libraries
Problem: AROS libraries don't use standard ELF symbol tables.
Solution:
- Create a symbol mapping table manually
- Use AROS resident libraries instead of dynamic loading
- Statically link JNI libraries when possible
Issue 4: Signal Handling Incompatibility
Problem: POSIX signals don't exist on AROS.
Solution:
- Disable JVM signal handlers
- Use --disable-signals configuration flag
- Implement minimal signal compatibility for SIGSEGV/SIGBUS only
11. API Quick Reference
Essential AROS APIs
API | Library | Purpose |
|---|
CreateNewProc() | dos.library | Create new process | AllocVec() | exec.library | Allocate memory | [quote]
|