From 863e04f19ef55cfc5d5dcd66e32259fa63cf3a21 Mon Sep 17 00:00:00 2001 From: IonutParau Date: Sat, 12 Jul 2025 18:42:38 +0200 Subject: [PATCH] the sound of progress - Medic TF2 --- TODO.md | 7 +- build.zig | 3 +- src/components/drive.c | 150 ++++++++++++++++++++++-------------- src/components/filesystem.c | 54 ++++++++++++- src/computer.c | 6 +- src/emulator.c | 84 +++++--------------- src/neonucleus.h | 39 ++++++---- src/testLuaArch.c | 2 +- src/utils.c | 30 ++++++++ 9 files changed, 231 insertions(+), 144 deletions(-) diff --git a/TODO.md b/TODO.md index b6a2cc2..1841cee 100644 --- a/TODO.md +++ b/TODO.md @@ -1,6 +1,6 @@ # Parity with Vanilla OC (only the stuff that makes sense for an emulator) -- in-memory version of `filesystem` and `drive` +- in-memory version of `filesystem` - `hologram` component - `computer` component - `modem` component @@ -18,7 +18,6 @@ # Bugfixes - Rework filesystem component to pre-process paths to ensure proper sandboxing and not allow arbitrary remote file access -- Ensure the recursive locks are used correctly to prevent race conditions - Do a huge audit at some point # The extra components @@ -35,10 +34,6 @@ - `tape_drive` component, compatible with Computronics, except maybe with proper seek times and support for multiple tapes - `cd_reader` and `cd_writer` components, to work with CDs -# API changes - -- move controls into the component instances instead of using getters, to boost performance - # Internal changes - use dynamic arrays for signals (and maybe components), but still keep the maximums to prevent memory hogging diff --git a/build.zig b/build.zig index 85f1b4c..12b170d 100644 --- a/build.zig +++ b/build.zig @@ -28,6 +28,7 @@ fn addEngineSources(b: *std.Build, opts: LibBuildOpts) *std.Build.Module { "src/components/eeprom.c", "src/components/filesystem.c", "src/components/drive.c", + "src/components/volatileDrive.c", "src/components/screen.c", "src/components/gpu.c", "src/components/keyboard.c", @@ -68,7 +69,7 @@ fn compileTheRightLua(b: *std.Build, target: std.Build.ResolvedTarget, version: const c = b.addObject(.{ .name = "lua", .link_libc = true, - .optimize = .ReleaseSafe, + .optimize = .ReleaseFast, .target = target, }); diff --git a/src/components/drive.c b/src/components/drive.c index 099f6e8..5b5dcd0 100644 --- a/src/components/drive.c +++ b/src/components/drive.c @@ -1,28 +1,58 @@ #include "../neonucleus.h" -typedef struct nni_drive { - nn_drive *funcs; +typedef struct nn_drive { + nn_refc refc; + nn_guard *lock; + nn_Context ctx; nn_size_t currentSector; -} nni_drive; + nn_driveTable table; + nn_driveControl ctrl; +} nn_drive; -void nn_drive_destroy(void *_, nn_component *component, nni_drive *drive) { - if(!nn_decRef(&drive->funcs->refc)) return; +nn_drive *nn_newDrive(nn_Context *context, nn_driveTable table, nn_driveControl control) { + nn_drive *d = nn_alloc(&context->allocator, sizeof(nn_drive)); + if(d == NULL) return NULL; + d->lock = nn_newGuard(context); + if(d->lock == NULL) { + nn_dealloc(&context->allocator, d, sizeof(nn_drive)); + return NULL; + } + d->refc = 1; + d->table = table; + d->ctrl = control; + d->currentSector = 0; + d->ctx = *context; + return d; +} - if(drive->funcs->deinit != NULL) { - drive->funcs->deinit(component, drive->funcs->userdata); +nn_guard *nn_getDriveLock(nn_drive *drive) { + return drive->lock; +} + +void nn_retainDrive(nn_drive *drive) { + nn_incRef(&drive->refc); +} + +nn_bool_t nn_destroyDrive(nn_drive *drive) { + if(!nn_decRef(&drive->refc)) return false; + + if(drive->table.deinit != NULL) { + drive->table.deinit(drive->table.userdata); } - nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(nn_getComputerOfComponent(component))); + nn_Context ctx = drive->ctx; - nn_dealloc(alloc, drive, sizeof(nni_drive)); + nn_deleteGuard(&ctx, drive->lock); + nn_dealloc(&ctx.allocator, drive, sizeof(nn_drive)); + return true; } -nn_driveControl nn_drive_getControl(nn_component *component, nni_drive *drive) { - return drive->funcs->control(component, drive->funcs->userdata); +void nn_drive_destroy(void *_, nn_component *component, nn_drive *drive) { + nn_destroyDrive(drive); } -void nni_drive_readCost(nn_component *component, nni_drive *drive) { - nn_driveControl ctrl = nn_drive_getControl(component, drive); +void nni_drive_readCost(nn_component *component, nn_drive *drive) { + nn_driveControl ctrl = drive->ctrl; nn_computer *computer = nn_getComputerOfComponent(component); nn_simulateBufferedIndirect(component, 1, ctrl.readSectorsPerTick); @@ -30,8 +60,8 @@ void nni_drive_readCost(nn_component *component, nni_drive *drive) { nn_removeEnergy(computer, ctrl.readEnergyPerSector); } -void nni_drive_writeCost(nn_component *component, nni_drive *drive) { - nn_driveControl ctrl = nn_drive_getControl(component, drive); +void nni_drive_writeCost(nn_component *component, nn_drive *drive) { + nn_driveControl ctrl = drive->ctrl; nn_computer *computer = nn_getComputerOfComponent(component); nn_simulateBufferedIndirect(component, 1, ctrl.writeSectorsPerTick); @@ -39,19 +69,19 @@ void nni_drive_writeCost(nn_component *component, nni_drive *drive) { nn_removeEnergy(computer, ctrl.writeEnergyPerSector); } -void nni_drive_seekTo(nn_component *component, nni_drive *drive, nn_size_t sector) { +void nni_drive_seekTo(nn_component *component, nn_drive *drive, nn_size_t sector) { sector = sector - 1; // switch to 0 to N-1 sector addressing, // which is much nicer to do math with // and Lua made a big oopsie. nn_size_t old = drive->currentSector; - nn_driveControl ctrl = nn_drive_getControl(component, drive); + nn_driveControl ctrl = drive->ctrl; if(ctrl.seekSectorsPerTick == 0) return; // seek latency disabled nn_computer *computer = nn_getComputerOfComponent(component); // Compute important constants - nn_size_t sectorSize = drive->funcs->getSectorSize(component, drive->funcs->userdata); - nn_size_t platterCount = drive->funcs->getPlatterCount(component, drive->funcs->userdata); - nn_size_t capacity = drive->funcs->getCapacity(component, drive->funcs->userdata); + nn_size_t sectorSize = drive->table.sectorSize; + nn_size_t platterCount = drive->table.platterCount; + nn_size_t capacity = drive->table.capacity; nn_size_t sectorsPerPlatter = (capacity / sectorSize) / platterCount; @@ -83,17 +113,19 @@ void nni_drive_seekTo(nn_component *component, nni_drive *drive, nn_size_t secto nn_removeEnergy(computer, ctrl.motorEnergyPerSector * moved); } -void nn_drive_getLabel(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { +void nn_drive_getLabel(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) { char buf[NN_LABEL_SIZE]; nn_size_t l = NN_LABEL_SIZE; - drive->funcs->getLabel(component, drive->funcs->userdata, buf, &l); + nn_lock(&drive->ctx, drive->lock); + drive->table.getLabel(drive->table.userdata, buf, &l); + nn_unlock(&drive->ctx, drive->lock); if(l == 0) { nn_return(computer, nn_values_nil()); } else { nn_return_string(computer, buf, l); } } -void nn_drive_setLabel(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { +void nn_drive_setLabel(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) { nn_size_t l = 0; nn_value label = nn_getArgument(computer, 0); const char *buf = nn_toString(label, &l); @@ -101,38 +133,42 @@ void nn_drive_setLabel(nni_drive *drive, void *_, nn_component *component, nn_co nn_setCError(computer, "bad label (string expected)"); return; } - l = drive->funcs->setLabel(component, drive->funcs->userdata, buf, l); + nn_lock(&drive->ctx, drive->lock); + l = drive->table.setLabel(drive->table.userdata, buf, l); + nn_unlock(&drive->ctx, drive->lock); nn_return_string(computer, buf, l); } -void nn_drive_getSectorSize(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { - nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata); +void nn_drive_getSectorSize(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) { + nn_size_t sector_size = drive->table.sectorSize; nn_return(computer, nn_values_integer(sector_size)); } -void nn_drive_getPlatterCount(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { - nn_size_t platter_count = drive->funcs->getPlatterCount(component, drive->funcs->userdata); +void nn_drive_getPlatterCount(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) { + nn_size_t platter_count = drive->table.platterCount; nn_return(computer, nn_values_integer(platter_count)); } -void nn_drive_getCapacity(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { - nn_size_t capacity = drive->funcs->getCapacity(component, drive->funcs->userdata); +void nn_drive_getCapacity(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) { + nn_size_t capacity = drive->table.capacity; nn_return(computer, nn_values_integer(capacity)); } -void nn_drive_readSector(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { +void nn_drive_readSector(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) { nn_value sectorValue = nn_getArgument(computer, 0); int sector = nn_toInt(sectorValue); - nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata); + nn_size_t sector_size = drive->table.sectorSize; // we leave the +1 intentionally to compare the end of the real sector - if (sector < 1 || (sector * sector_size > drive->funcs->getCapacity(component, drive->funcs->userdata))) { + if (sector < 1 || (sector * sector_size > drive->table.capacity)) { nn_setCError(computer, "bad argument #1 (sector out of range)"); return; } char buf[sector_size]; - drive->funcs->readSector(component, drive->funcs->userdata, sector, buf); + nn_lock(&drive->ctx, drive->lock); + drive->table.readSector(drive->table.userdata, sector, buf); + nn_unlock(&drive->ctx, drive->lock); nn_return_string(computer, buf, sector_size); } -void nn_drive_writeSector(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { +void nn_drive_writeSector(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) { nn_value sectorValue = nn_getArgument(computer, 0); int sector = nn_toInt(sectorValue); - nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata); + nn_size_t sector_size = drive->table.sectorSize; nn_value bufValue = nn_getArgument(computer, 1); nn_size_t buf_size = 0; @@ -142,34 +178,40 @@ void nn_drive_writeSector(nni_drive *drive, void *_, nn_component *component, nn return; } // we leave the +1 intentionally to compare the end of the real sector - if (sector < 1 || (sector * sector_size > drive->funcs->getCapacity(component, drive->funcs->userdata))) { + if (sector < 1 || (sector * sector_size > drive->table.capacity)) { nn_setCError(computer, "bad argument #1 (sector out of range)"); return; } - drive->funcs->writeSector(component, drive->funcs->userdata, sector, buf); + nn_lock(&drive->ctx, drive->lock); + drive->table.writeSector(drive->table.userdata, sector, buf); + nn_unlock(&drive->ctx, drive->lock); + + nn_return_boolean(computer, true); } -void nn_drive_readByte(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { +void nn_drive_readByte(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) { nn_value offsetValue = nn_getArgument(computer, 0); nn_size_t disk_offset = nn_toInt(offsetValue) - 1; - nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata); + nn_size_t sector_size = drive->table.sectorSize; int sector = (disk_offset / sector_size) + 1; nn_size_t sector_offset = disk_offset % sector_size; - if (disk_offset >= drive->funcs->getCapacity(component, drive->funcs->userdata)) { + if (disk_offset >= drive->table.capacity) { nn_setCError(computer, "bad argument #1 (index out of range)"); return; } char buf[sector_size]; - drive->funcs->readSector(component, drive->funcs->userdata, sector, buf); + nn_lock(&drive->ctx, drive->lock); + drive->table.readSector(drive->table.userdata, sector, buf); + nn_unlock(&drive->ctx, drive->lock); nn_return(computer, nn_values_integer(buf[sector_offset])); } -void nn_drive_writeByte(nni_drive *drive, void *_, nn_component *component, nn_computer *computer) { +void nn_drive_writeByte(nn_drive *drive, void *_, nn_component *component, nn_computer *computer) { nn_value offsetValue = nn_getArgument(computer, 0); nn_value writeValue = nn_getArgument(computer, 1); nn_size_t disk_offset = nn_toInt(offsetValue) - 1; nn_intptr_t write = nn_toInt(writeValue); - nn_size_t sector_size = drive->funcs->getSectorSize(component, drive->funcs->userdata); + nn_size_t sector_size = drive->table.sectorSize; int sector = (disk_offset / sector_size) + 1; nn_size_t sector_offset = disk_offset % sector_size; @@ -177,16 +219,20 @@ void nn_drive_writeByte(nni_drive *drive, void *_, nn_component *component, nn_c nn_setCError(computer, "bad argument #2 (byte out of range)"); return; } - if (disk_offset >= drive->funcs->getCapacity(component, drive->funcs->userdata)) { + if (disk_offset >= drive->table.capacity) { nn_setCError(computer, "bad argument #1 (index out of range)"); return; } + nn_lock(&drive->ctx, drive->lock); char buf[sector_size]; - drive->funcs->readSector(component, drive->funcs->userdata, sector, buf); + drive->table.readSector(drive->table.userdata, sector, buf); buf[sector_offset] = write; - drive->funcs->writeSector(component, drive->funcs->userdata, sector, buf); + drive->table.writeSector(drive->table.userdata, sector, buf); + nn_unlock(&drive->ctx, drive->lock); + + nn_return_boolean(computer, true); } void nn_loadDriveTable(nn_universe *universe) { @@ -205,15 +251,7 @@ void nn_loadDriveTable(nn_universe *universe) { } nn_component *nn_addDrive(nn_computer *computer, nn_address address, int slot, nn_drive *drive) { - nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(computer)); - nni_drive *d = nn_alloc(alloc, sizeof(nni_drive)); - d->currentSector = 0; - d->funcs = drive; nn_componentTable *driveTable = nn_queryUserdata(nn_getUniverse(computer), "NN:DRIVE"); - nn_component *c = nn_newComponent(computer, address, slot, driveTable, drive); - if(c == NULL) { - nn_dealloc(alloc, d, sizeof(nni_drive)); - } - return c; + return nn_newComponent(computer, address, slot, driveTable, drive); } diff --git a/src/components/filesystem.c b/src/components/filesystem.c index 2327ea7..c312e60 100644 --- a/src/components/filesystem.c +++ b/src/components/filesystem.c @@ -58,19 +58,28 @@ nn_bool_t nn_destroyFilesystem(nn_filesystem *fs) { } nn_size_t nn_fs_getSpaceUsed(nn_filesystem *fs) { - if(fs->spaceUsedCache != 0) return fs->spaceUsedCache; + nn_lock(&fs->ctx, fs->lock); + if(fs->spaceUsedCache != 0) { + nn_unlock(&fs->ctx, fs->lock); + return fs->spaceUsedCache; + } nn_size_t spaceUsed = fs->table.spaceUsed(fs->table.userdata); fs->spaceUsedCache = spaceUsed; + nn_unlock(&fs->ctx, fs->lock); return spaceUsed; } void nn_fs_invalidateSpaceUsed(nn_filesystem *fs) { + nn_lock(&fs->ctx, fs->lock); fs->spaceUsedCache = 0; + nn_unlock(&fs->ctx, fs->lock); } nn_size_t nn_fs_getSpaceRemaining(nn_filesystem *fs) { + nn_lock(&fs->ctx, fs->lock); nn_size_t used = nn_fs_getSpaceUsed(fs); nn_size_t total = fs->table.spaceTotal; + nn_unlock(&fs->ctx, fs->lock); return total - used; } @@ -78,7 +87,9 @@ void *nn_fs_unwrapFD(nn_filesystem *fs, nn_size_t fd) { if(fd >= NN_MAX_OPEN_FILES) { return NULL; } + nn_lock(&fs->ctx, fs->lock); void *file = fs->files[fd]; + nn_unlock(&fs->ctx, fs->lock); if(file == NULL) { return NULL; } @@ -134,7 +145,9 @@ void nn_fs_createCost(nn_filesystem *fs, nn_size_t count, nn_component *componen void nn_fs_getLabel(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) { char buf[NN_LABEL_SIZE]; nn_size_t l = NN_LABEL_SIZE; + nn_lock(&fs->ctx, fs->lock); fs->table.getLabel(fs->table.userdata, buf, &l); + nn_unlock(&fs->ctx, fs->lock); if(l == 0) { nn_return(computer, nn_values_nil()); } else { @@ -152,7 +165,9 @@ void nn_fs_setLabel(nn_filesystem *fs, void *_, nn_component *component, nn_comp nn_setCError(computer, "bad label (string expected)"); return; } + nn_lock(&fs->ctx, fs->lock); l = fs->table.setLabel(fs->table.userdata, buf, l); + nn_unlock(&fs->ctx, fs->lock); nn_return_string(computer, buf, l); nn_fs_writeCost(fs, l, component); @@ -168,7 +183,9 @@ void nn_fs_spaceTotal(nn_filesystem *fs, void *_, nn_component *component, nn_co } void nn_fs_isReadOnly(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) { + nn_lock(&fs->ctx, fs->lock); nn_return_boolean(computer, fs->table.isReadOnly(fs->table.userdata)); + nn_unlock(&fs->ctx, fs->lock); } void nn_fs_size(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) { @@ -183,7 +200,9 @@ void nn_fs_size(nn_filesystem *fs, void *_, nn_component *component, nn_computer return; } + nn_lock(&fs->ctx, fs->lock); nn_size_t byteSize = fs->table.size(fs->table.userdata, path); + nn_unlock(&fs->ctx, fs->lock); nn_return(computer, nn_values_integer(byteSize)); } @@ -200,7 +219,9 @@ void nn_fs_remove(nn_filesystem *fs, void *_, nn_component *component, nn_comput return; } + nn_lock(&fs->ctx, fs->lock); nn_size_t removed = fs->table.remove(fs->table.userdata, path); + nn_unlock(&fs->ctx, fs->lock); nn_return_boolean(computer, removed > 0); nn_fs_removeCost(fs, removed, component); @@ -218,7 +239,9 @@ void nn_fs_lastModified(nn_filesystem *fs, void *_, nn_component *component, nn_ return; } + nn_lock(&fs->ctx, fs->lock); nn_size_t t = fs->table.lastModified(fs->table.userdata, path); + nn_unlock(&fs->ctx, fs->lock); // OpenOS does BULLSHIT with this thing, dividing it by 1000 and expecting it to be // fucking usable as a date, meaning it needs to be an int. @@ -251,7 +274,9 @@ void nn_fs_rename(nn_filesystem *fs, void *_, nn_component *component, nn_comput return; } + nn_lock(&fs->ctx, fs->lock); nn_size_t movedCount = fs->table.rename(fs->table.userdata, from, to); + nn_unlock(&fs->ctx, fs->lock); nn_return(computer, nn_values_boolean(movedCount > 0)); nn_fs_removeCost(fs, movedCount, component); @@ -270,7 +295,9 @@ void nn_fs_exists(nn_filesystem *fs, void *_, nn_component *component, nn_comput return; } + nn_lock(&fs->ctx, fs->lock); nn_return_boolean(computer, fs->table.exists(fs->table.userdata, path)); + nn_unlock(&fs->ctx, fs->lock); } void nn_fs_isDirectory(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) { @@ -285,7 +312,9 @@ void nn_fs_isDirectory(nn_filesystem *fs, void *_, nn_component *component, nn_c return; } + nn_lock(&fs->ctx, fs->lock); nn_return_boolean(computer, fs->table.isDirectory(fs->table.userdata, path)); + nn_unlock(&fs->ctx, fs->lock); } void nn_fs_makeDirectory(nn_filesystem *fs, void *_, nn_component *component, nn_computer *computer) { @@ -300,7 +329,9 @@ void nn_fs_makeDirectory(nn_filesystem *fs, void *_, nn_component *component, nn return; } + nn_lock(&fs->ctx, fs->lock); nn_return_boolean(computer, fs->table.makeDirectory(fs->table.userdata, path)); + nn_unlock(&fs->ctx, fs->lock); nn_fs_createCost(fs, 1, component); } @@ -320,7 +351,9 @@ void nn_fs_list(nn_filesystem *fs, void *_, nn_component *component, nn_computer nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(computer)); nn_size_t fileCount = 0; + nn_lock(&fs->ctx, fs->lock); char **files = fs->table.list(alloc, fs->table.userdata, path, &fileCount); + nn_unlock(&fs->ctx, fs->lock); if(files != NULL) { // operation succeeded @@ -352,6 +385,7 @@ void nn_fs_open(nn_filesystem *fs, void *_, nn_component *component, nn_computer mode = "r"; } + nn_lock(&fs->ctx, fs->lock); // technically wrongfully if(!fs->table.exists(fs->table.userdata, path)) { nn_fs_createCost(fs, 1, component); @@ -361,15 +395,18 @@ void nn_fs_open(nn_filesystem *fs, void *_, nn_component *component, nn_computer while(fs->files[fd] != NULL) { fd++; if(fd == NN_MAX_OPEN_FILES) { + nn_unlock(&fs->ctx, fs->lock); nn_setCError(computer, "too many open files"); return; } } void *file = fs->table.open(fs->table.userdata, path, mode); if(file == NULL) { + nn_unlock(&fs->ctx, fs->lock); nn_setCError(computer, "no such file or directory"); return; } + nn_unlock(&fs->ctx, fs->lock); fs->files[fd] = file; nn_return(computer, nn_values_integer(fd)); } @@ -383,10 +420,12 @@ void nn_fs_close(nn_filesystem *fs, void *_, nn_component *component, nn_compute return; } + nn_lock(&fs->ctx, fs->lock); nn_bool_t closed = fs->table.close(fs->table.userdata, file); if(closed) { fs->files[fd] = NULL; } + nn_unlock(&fs->ctx, fs->lock); nn_return(computer, nn_values_boolean(closed)); } @@ -402,15 +441,18 @@ void nn_fs_write(nn_filesystem *fs, void *_, nn_component *component, nn_compute return; } - size_t spaceRemaining = nn_fs_getSpaceRemaining(fs); + nn_lock(&fs->ctx, fs->lock); + nn_size_t spaceRemaining = nn_fs_getSpaceRemaining(fs); // overwriting would still work but OC does the same thing so... if(spaceRemaining < len) { + nn_unlock(&fs->ctx, fs->lock); nn_setCError(computer, "out of space"); return; } void *file = nn_fs_unwrapFD(fs, fd); if(file == NULL) { + nn_unlock(&fs->ctx, fs->lock); nn_setCError(computer, "bad file descriptor"); return; } @@ -418,6 +460,7 @@ void nn_fs_write(nn_filesystem *fs, void *_, nn_component *component, nn_compute nn_bool_t written = fs->table.write(fs->table.userdata, file, buf, len); nn_return(computer, nn_values_boolean(written)); if(written) nn_fs_invalidateSpaceUsed(fs); + nn_unlock(&fs->ctx, fs->lock); nn_fs_writeCost(fs, len, component); } @@ -433,8 +476,10 @@ void nn_fs_read(nn_filesystem *fs, void *_, nn_component *component, nn_computer if(len > capacity) len = capacity; nn_size_t byteLen = len; + nn_lock(&fs->ctx, fs->lock); void *file = nn_fs_unwrapFD(fs, fd); if(file == NULL) { + nn_unlock(&fs->ctx, fs->lock); nn_setCError(computer, "bad file descriptor"); return; } @@ -442,11 +487,13 @@ void nn_fs_read(nn_filesystem *fs, void *_, nn_component *component, nn_computer nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(computer)); char *buf = nn_alloc(alloc, byteLen); if(buf == NULL) { + nn_unlock(&fs->ctx, fs->lock); nn_setCError(computer, "out of memory"); return; } nn_size_t readLen = fs->table.read(fs->table.userdata, file, buf, byteLen); + nn_unlock(&fs->ctx, fs->lock); if(readLen > 0) { // Nothing read means EoF. nn_return_string(computer, buf, readLen); @@ -480,13 +527,16 @@ void nn_fs_seek(nn_filesystem *fs, void *_, nn_component *component, nn_computer return; } + nn_lock(&fs->ctx, fs->lock); void *file = nn_fs_unwrapFD(fs, fd); if(file == NULL) { + nn_unlock(&fs->ctx, fs->lock); nn_setCError(computer, "bad file descriptor"); return; } nn_size_t pos = fs->table.seek(fs->table.userdata, file, whence, off); + nn_unlock(&fs->ctx, fs->lock); nn_return_integer(computer, pos); } diff --git a/src/computer.c b/src/computer.c index a9a9823..d12dd4b 100644 --- a/src/computer.c +++ b/src/computer.c @@ -367,7 +367,11 @@ nn_component *nn_newComponent(nn_computer *computer, nn_address address, int slo computer->componentLen++; } - c->address = nn_strdup(&computer->universe->ctx.allocator, address); + if(address == NULL) { + c->address = nn_randomUUID(&computer->universe->ctx); + } else { + c->address = nn_strdup(&computer->universe->ctx.allocator, address); + } if(c->address == NULL) return NULL; c->table = table; c->slot = slot; diff --git a/src/emulator.c b/src/emulator.c index 656cf61..15f920a 100644 --- a/src/emulator.c +++ b/src/emulator.c @@ -1,5 +1,4 @@ #include -#include #include #include #include @@ -291,47 +290,6 @@ bool ne_fs_exists(nn_address addr, const char *path) { return FileExists(p) || DirectoryExists(p); } -typedef struct ne_drive { - FILE *file; -} ne_drive; - -void ne_drive_close(nn_component *component, ne_drive *drive) { - fclose(drive->file); -} -nn_driveControl ne_drive_getControl(nn_component *component, ne_drive *_) { - return (nn_driveControl){}; -} -size_t ne_drive_getPlatterCount(nn_component *component, ne_drive *_) { - return 1; -} -size_t ne_drive_getSectorSize(nn_component *component, ne_drive *_) { - return 512; -} -size_t ne_drive_getCapacity(nn_component *component, ne_drive *drive) { - fseek(drive->file, 0, SEEK_END); - return ftell(drive->file); -} -void ne_drive_readSector(nn_component *component, ne_drive *drive, int shifted_sector, char *buf) { - int sector = shifted_sector - 1; - size_t sectorSize = ne_drive_getSectorSize(component, drive); - - size_t offset = sector * sectorSize; - fseek(drive->file, offset, SEEK_SET); - fread(buf, sizeof(char), sectorSize, drive->file); -} -void ne_drive_writeSector(nn_component *component, ne_drive *drive, int shifted_sector, const char *buf) { - int sector = shifted_sector - 1; - size_t sectorSize = ne_drive_getSectorSize(component, drive); - - size_t offset = sector * sectorSize; - fseek(drive->file, offset, SEEK_SET); - fwrite(buf, sizeof(char), sectorSize, drive->file); - - // this is probably not needed but i believe someone isn't running the deinit - fflush(drive->file); -} - - int keycode_to_oc(int keycode) { switch (keycode) { case KEY_NULL: @@ -656,7 +614,7 @@ int main() { nn_eeprom *genericEEPROM = nn_newEEPROM(&ctx, genericEEPROMTable, ne_eeprom_ctrl); - nn_addEeprom(computer, "luaBios.lua", 0, genericEEPROM); + nn_addEeprom(computer, NULL, 0, genericEEPROM); nn_address fsFolder = "OpenOS"; nn_filesystemTable genericFSTable = { @@ -682,28 +640,26 @@ int main() { .seek = (void *)ne_fs_seek, }; nn_filesystem *genericFS = nn_newFilesystem(&ctx, genericFSTable, ne_fs_ctrl); - nn_addFileSystem(computer, fsFolder, 1, genericFS); + nn_addFileSystem(computer, NULL, 1, genericFS); - ne_drive drive = { - .file = fopen("data/drive.img", "r+") + nn_vdriveOptions vdriveOpts = { + .sectorSize = 512, + .capacity = 1*1024*1024, + .platterCount = 1, }; - assert(drive.file != NULL); - - nn_drive genericDrive = { - .refc = 0, - .userdata = &drive, - .deinit = (void *)ne_drive_close, - .control = (void *)ne_drive_getControl, - .getLabel = ne_fs_getLabel, - .setLabel = ne_fs_setLabel, - .getPlatterCount = (void *)ne_drive_getPlatterCount, - .getSectorSize = (void *)ne_drive_getSectorSize, - .getCapacity = (void *)ne_drive_getCapacity, - .readSector = (void *)ne_drive_readSector, - .writeSector = (void *)ne_drive_writeSector, + nn_driveControl vdriveCtrl = { + .readSectorsPerTick = 32768, + .writeSectorsPerTick = 16384, + .seekSectorsPerTick = 8192, + .readHeatPerSector = 0.0015, + .writeHeatPerSector = 0.015, + .motorHeatPerSector = 0.000005, + .readEnergyPerSector = 0.0015, + .writeEnergyPerSector = 0.015, + .motorEnergyPerSector = 0.00005, }; - - nn_addDrive(computer, "drive.img", 4, &genericDrive); + nn_drive *genericDrive = nn_volatileDrive(&ctx, vdriveOpts, vdriveCtrl, NULL); + nn_addDrive(computer, NULL, 4, genericDrive); int maxWidth = 80, maxHeight = 32; @@ -711,7 +667,7 @@ int main() { nn_setDepth(s, 4); // looks cool nn_addKeyboard(s, "shitty keyboard"); nn_mountKeyboard(computer, "shitty keyboard", 2); - nn_addScreen(computer, "Main Screen", 2, s); + nn_addScreen(computer, NULL, 2, s); ne_premappedPixel *premap = ne_allocPremap(maxWidth, maxHeight); @@ -731,7 +687,7 @@ int main() { .energyPerVRAMChange = 0.0015, }; - nn_addGPU(computer, "RTX 6090", 3, &gpuCtrl); + nn_addGPU(computer, NULL, 3, &gpuCtrl); SetConfigFlags(FLAG_WINDOW_RESIZABLE); InitWindow(800, 600, "emulator"); diff --git a/src/neonucleus.h b/src/neonucleus.h index da38081..2a3c85a 100644 --- a/src/neonucleus.h +++ b/src/neonucleus.h @@ -196,6 +196,7 @@ double nn_randf(nn_Rng *rng); // returns from 0 to 1 (exclusive) double nn_randfe(nn_Rng *rng); + typedef struct nn_Context { nn_Alloc allocator; nn_LockManager lockManager; @@ -281,6 +282,7 @@ void nn_dealloc(nn_Alloc *alloc, void *memory, nn_size_t size); char *nn_strdup(nn_Alloc *alloc, const char *s); void *nn_memdup(nn_Alloc *alloc, const void *buf, nn_size_t len); void nn_deallocStr(nn_Alloc *alloc, char *s); +nn_address nn_randomUUID(nn_Context *ctx); nn_guard *nn_newGuard(nn_Context *context); void nn_lock(nn_Context *context, nn_guard *guard); @@ -691,28 +693,39 @@ typedef struct nn_driveControl { nn_bool_t reversable; } nn_driveControl; -typedef struct nn_drive { - nn_refc refc; +typedef struct nn_driveTable { void *userdata; - void (*deinit)(nn_component *component, void *userdata); + void (*deinit)(void *userdata); - nn_driveControl (*control)(nn_component *component, void *userdata); - void (*getLabel)(nn_component *component, void *userdata, char *buf, nn_size_t *buflen); - nn_size_t (*setLabel)(nn_component *component, void *userdata, const char *buf, nn_size_t buflen); + void (*getLabel)(void *userdata, char *buf, nn_size_t *buflen); + nn_size_t (*setLabel)(void *userdata, const char *buf, nn_size_t buflen); - nn_size_t (*getPlatterCount)(nn_component *component, void *userdata); - nn_size_t (*getCapacity)(nn_component *component, void *userdata); - nn_size_t (*getSectorSize)(nn_component *component, void *userdata); + nn_size_t platterCount; + nn_size_t capacity; + nn_size_t sectorSize; // sectors start at 1 as per OC. - void (*readSector)(nn_component *component, void *userdata, int sector, char *buf); - void (*writeSector)(nn_component *component, void *userdata, int sector, const char *buf); + void (*readSector)(void *userdata, int sector, char *buf); + void (*writeSector)(void *userdata, int sector, const char *buf); // readByte and writeByte will internally use readSector and writeSector. This is to ensure they are handled *consistently.* // Also makes the interface less redundant -} nn_drive; +} nn_driveTable; + +typedef struct nn_vdriveOptions { + nn_size_t sectorSize; + nn_size_t platterCount; + nn_size_t capacity; +} nn_vdriveOptions; + +typedef struct nn_drive nn_drive; + +nn_drive *nn_newDrive(nn_Context *context, nn_driveTable table, nn_driveControl control); +nn_drive *nn_volatileDrive(nn_Context *context, nn_vdriveOptions opts, nn_driveControl control, const char *initialData); +nn_guard *nn_getDriveLock(nn_drive *drive); +void nn_retainDrive(nn_drive *drive); +nn_bool_t nn_destroyDrive(nn_drive *drive); -nn_drive *nn_volatileDrive(nn_size_t capacity, nn_size_t platterCount, nn_driveControl *control); nn_component *nn_addDrive(nn_computer *computer, nn_address address, int slot, nn_drive *drive); // Screens and GPUs diff --git a/src/testLuaArch.c b/src/testLuaArch.c index 667058b..b59d53a 100644 --- a/src/testLuaArch.c +++ b/src/testLuaArch.c @@ -59,12 +59,12 @@ const char *testLuaArch_pushlstring(lua_State *L, const char *s, size_t len) { } return lua_pushlstring(L, s, len); } + const char *testLuaArch_pushstring(lua_State *L, const char *s) { size_t len = strlen(s); return testLuaArch_pushlstring(L, s, len); } - void *testLuaArch_alloc(testLuaArch *arch, void *ptr, size_t osize, size_t nsize) { nn_Alloc *alloc = nn_getAllocator(nn_getUniverse(arch->computer)); if(nsize == 0) { diff --git a/src/utils.c b/src/utils.c index 74a40f4..c4d15b5 100644 --- a/src/utils.c +++ b/src/utils.c @@ -104,6 +104,36 @@ void nn_deallocStr(nn_Alloc *alloc, char *s) { nn_dealloc(alloc, s, nn_strlen(s)+1); } +static void nni_randomHex(nn_Context *ctx, char *buf, nn_size_t len) { + const char *hex = "0123456789abcdef"; + + for(nn_size_t i = 0; i < len; i++) { + int r = nn_rand(&ctx->rng) % 16; + buf[i] = hex[r]; + } +} + +nn_address nn_randomUUID(nn_Context *ctx) { + nn_address addr = nn_alloc(&ctx->allocator, 37); + if(addr == NULL) return NULL; + nni_randomHex(ctx, addr + 0, 8); + addr[8] = '-'; + nni_randomHex(ctx, addr + 9, 4); + addr[13] = '-'; + nni_randomHex(ctx, addr + 14, 4); + addr[18] = '-'; + nni_randomHex(ctx, addr + 19, 4); + addr[23] = '-'; + nni_randomHex(ctx, addr + 24, 12); + addr[36] = '\0'; + + + // UUIDv4 variant 1 + addr[14] = '4'; + addr[19] = '1'; + return addr; +} + nn_size_t nn_rand(nn_Rng *rng) { return rng->proc(rng->userdata); }