the sound of progress

- Medic TF2
This commit is contained in:
2025-07-12 18:42:38 +02:00
parent af1244b829
commit 863e04f19e
9 changed files with 231 additions and 144 deletions

View File

@@ -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);
}

View File

@@ -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);
}