feat: extend pipe with pipeWrite and pipeHasData
This commit is contained in:
1 parent
43e3013260
commit
7c42af8790
2 files changed
+151
No files matched your search
+130
@@ -159,3 +159,133 @@ int64 pipeRead(int handle, void* buffer, uint64 length)
|
|||||||
if (p->writers == 0 && p->everHadWriter)
|
if (p->writers == 0 && p->everHadWriter)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 pipeWrite(int handle, const void* buffer, uint64 length)
|
||||||
|
{
|
||||||
|
Pipe* p = pipeAt(handle);
|
||||||
|
if (!p)
|
||||||
|
return -1;
|
||||||
|
/* Symmetric with pipeRead's EOF check above: only a reader that WAS
|
||||||
|
attached and left counts as a broken pipe. */
|
||||||
|
if (p->readers == 0 && p->everHadReader)
|
||||||
|
return -1;
|
||||||
|
if (length == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (ringIsFull(&p->ring))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
usize put = ringWrite(&p->ring, (const uint8*)buffer, (usize)length);
|
||||||
|
/* Writing adds ring data: any reader blocked on "buffer empty" may now
|
||||||
|
be able to proceed, so give it a chance to recheck. */
|
||||||
|
schedWakeChannel((const void*)p);
|
||||||
|
schedWakeChannel(schedPollChannel());
|
||||||
|
return (int64)put;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pipeHasData(int handle)
|
||||||
|
{
|
||||||
|
Pipe* p = pipeAt(handle);
|
||||||
|
if (!p)
|
||||||
|
return false;
|
||||||
|
return !ringIsEmpty(&p->ring) || (p->writers == 0 && p->everHadWriter);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pipeHasSpace(int handle)
|
||||||
|
{
|
||||||
|
Pipe* p = pipeAt(handle);
|
||||||
|
if (!p)
|
||||||
|
return false;
|
||||||
|
return !ringIsFull(&p->ring);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 pipeReadBlocking(int handle, void* buffer, uint64 length)
|
||||||
|
{
|
||||||
|
Pipe* p = pipeAt(handle);
|
||||||
|
if (!p)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int64 result = pipeRead(handle, buffer, length);
|
||||||
|
if (result != -1)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
schedBlockCurrent((const void*)p);
|
||||||
|
halt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 pipeWriteBlocking(int handle, const void* buffer, uint64 length)
|
||||||
|
{
|
||||||
|
Pipe* p = pipeAt(handle);
|
||||||
|
if (!p)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
int64 result = pipeWrite(handle, buffer, length);
|
||||||
|
if (result != -1)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
/* A reader that attached and then left is a broken pipe: a terminal
|
||||||
|
condition no amount of waiting will ever resolve, unlike a merely
|
||||||
|
full buffer (or a pipeCreateDetached handle whose reader simply
|
||||||
|
has not attached yet). */
|
||||||
|
if (pipeWriteBroken(handle))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
schedBlockCurrent((const void*)p);
|
||||||
|
halt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pipeReleaseIfUnused(int handle)
|
||||||
|
{
|
||||||
|
Pipe* p = &pipes[handle];
|
||||||
|
if (p->readers == 0 && p->writers == 0)
|
||||||
|
p->used = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void pipeCloseRead(int handle)
|
||||||
|
{
|
||||||
|
Pipe* p = pipeAt(handle);
|
||||||
|
if (!p)
|
||||||
|
return;
|
||||||
|
if (p->readers > 0)
|
||||||
|
p->readers--;
|
||||||
|
/* A writer parked on "buffer full" must be woken to discover the pipe is
|
||||||
|
now broken instead of waiting forever for space that will never free
|
||||||
|
up on its own. */
|
||||||
|
if (p->readers == 0) {
|
||||||
|
schedWakeChannel((const void*)p);
|
||||||
|
schedWakeChannel(schedPollChannel());
|
||||||
|
}
|
||||||
|
pipeReleaseIfUnused(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void pipeCloseWrite(int handle)
|
||||||
|
{
|
||||||
|
Pipe* p = pipeAt(handle);
|
||||||
|
if (!p)
|
||||||
|
return;
|
||||||
|
if (p->writers > 0)
|
||||||
|
p->writers--;
|
||||||
|
/* A reader parked on "buffer empty" must be woken to discover true
|
||||||
|
end-of-file instead of waiting forever for data that will never
|
||||||
|
arrive. */
|
||||||
|
if (p->writers == 0) {
|
||||||
|
schedWakeChannel((const void*)p);
|
||||||
|
schedWakeChannel(schedPollChannel());
|
||||||
|
}
|
||||||
|
pipeReleaseIfUnused(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pipeDestroyIfUnattached(int handle)
|
||||||
|
{
|
||||||
|
Pipe* p = pipeAt(handle);
|
||||||
|
if (!p || p->readers != 0 || p->writers != 0)
|
||||||
|
return false;
|
||||||
|
p->used = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
@@ -96,9 +96,30 @@ void pmmInit(uint64 multibootInfo, uint64 protectedEnd)
|
|||||||
|
|
||||||
frameCount = highestAddr / frameSize;
|
frameCount = highestAddr / frameSize;
|
||||||
|
|
||||||
|
/* The bitmap itself must never overlap live data this function still
|
||||||
|
needs to read (or that anything else placed physically-here still
|
||||||
|
needs): the loaded kernel image, the multiboot module the caller has
|
||||||
|
already claimed via protectedEnd (typically the initrd, see
|
||||||
|
kmain.c), AND the multiboot info structure this very function is
|
||||||
|
reading `mmap` out of via endAddr, computed above. That last one is
|
||||||
|
not academic -- GRUB places the multiboot2 info block immediately
|
||||||
|
after the last module it loads, so protectedEnd (the module's own
|
||||||
|
end) and multibootInfo's start can legitimately land on the exact
|
||||||
|
same address. Anchoring on protectedEnd alone would then place the
|
||||||
|
bitmap ON TOP of the live mmap tag, and the memset just below would
|
||||||
|
zero out every entry's baseAddr/length/type with 0xFF *before* the
|
||||||
|
markFree pass a few lines down ever reads them -- silently losing
|
||||||
|
the entire usable-memory picture and leaving every frame "used"
|
||||||
|
forever. Growing the initrd (adding another user program, say) is
|
||||||
|
exactly what nudges protectedEnd into colliding with endAddr, so
|
||||||
|
this is not a hypothetical: it reproduced on the very next boot after
|
||||||
|
tools/mktar's ramdisk grew past whatever margin happened to exist
|
||||||
|
before. */
|
||||||
uint64 bitmapAnchor = (uint64)kernelPhysEnd;
|
uint64 bitmapAnchor = (uint64)kernelPhysEnd;
|
||||||
if (protectedEnd > bitmapAnchor)
|
if (protectedEnd > bitmapAnchor)
|
||||||
bitmapAnchor = protectedEnd;
|
bitmapAnchor = protectedEnd;
|
||||||
|
if (endAddr > bitmapAnchor)
|
||||||
|
bitmapAnchor = endAddr;
|
||||||
bitmap = (uint8*)alignUp(bitmapAnchor, frameSize);
|
bitmap = (uint8*)alignUp(bitmapAnchor, frameSize);
|
||||||
uint64 bitmapBytes = (frameCount + 7) / 8;
|
uint64 bitmapBytes = (frameCount + 7) / 8;
|
||||||
memset(bitmap, 0xFF, bitmapBytes);
|
memset(bitmap, 0xFF, bitmapBytes);
|
||||||
|
|||||||
Reference in new issue
Block a user