mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-06 03:08:31 +00:00
Make some minor fixups to bug reporting, etc.
This commit is contained in:
parent
84764ce7b8
commit
3f015b1e51
31 changed files with 244 additions and 134 deletions
|
@ -309,7 +309,7 @@ void LoadRelationships(int argc, char *argv[]) {
|
|||
for (i = 0; i < threads; ++i) {
|
||||
if (_spawn(LoadRelationshipsWorker, (void *)(intptr_t)i, th + i) == -1) {
|
||||
pthread_mutex_lock(&reportlock);
|
||||
kprintf("error: clone(%d) failed %m\n", i);
|
||||
kprintf("error: _spawn(%d) failed %m\n", i);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
@ -420,7 +420,7 @@ void Explore(void) {
|
|||
for (i = 0; i < threads; ++i) {
|
||||
if (_spawn(Diver, (void *)(intptr_t)i, th + i) == -1) {
|
||||
pthread_mutex_lock(&reportlock);
|
||||
kprintf("error: clone(%d) failed %m\n", i);
|
||||
kprintf("error: _spawn(%d) failed %m\n", i);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2015,6 +2015,48 @@ UNIX MODULE
|
|||
This system call returns twice. The parent process gets the nonzero
|
||||
pid. The child gets zero.
|
||||
|
||||
Here's a simple usage example of creating subprocesses, where we
|
||||
fork off a child worker from a main process hook callback to do some
|
||||
independent chores, such as sending an HTTP request back to redbean.
|
||||
|
||||
-- as soon as server starts, make a fetch to the server
|
||||
-- then signal redbean to shutdown when fetch is complete
|
||||
local onServerStart = function()
|
||||
if assert(unix.fork()) == 0 then
|
||||
local ok, headers, body = Fetch('http://127.0.0.1:8080/test')
|
||||
unix.kill(unix.getppid(), unix.SIGTERM)
|
||||
unix.exit(0)
|
||||
end
|
||||
end
|
||||
OnServerStart = onServerStart
|
||||
|
||||
We didn't need to use wait() here, because (a) we want redbean to go
|
||||
back to what it was doing before as the Fetch() completes, and (b)
|
||||
redbean's main process already has a zombie collector. However it's
|
||||
a moot point, since once the fetch is done, the child process then
|
||||
asks redbean to gracefully shutdown by sending SIGTERM its parent.
|
||||
|
||||
This is actually a situation where we *must* use fork, because the
|
||||
purpose of the main redbean process is to call accept() and create
|
||||
workers. So if we programmed redbean to use the main process to send
|
||||
a blocking request to itself instead, then redbean would deadlock
|
||||
and never be able to accept() the client.
|
||||
|
||||
While deadlocking is an extreme example, the truth is that latency
|
||||
issues can crop up for the same reason that just cause jitter
|
||||
instead, and as such, can easily go unnoticed. For example, if you
|
||||
do something that takes longer than a few milliseconds from inside
|
||||
your redbean heartbeat, then that's a few milliseconds in which
|
||||
redbean is no longer concurrent, and tail latency is being added to
|
||||
its ability to accept new connections. fork() does a great job at
|
||||
solving this.
|
||||
|
||||
If you're not sure how long something will take, then when in doubt,
|
||||
fork off a process. You can then report its completion to something
|
||||
like SQLite. Redbean makes having lots of processes cheap. On Linux
|
||||
they're about as lightweight as what heavyweight environments call
|
||||
greenlets. You can easily have 10,000 Redbean workers on one PC.
|
||||
|
||||
Here's some benchmarks for fork() performance across platforms:
|
||||
|
||||
Linux 5.4 fork l: 97,200𝑐 31,395𝑛𝑠 [metal]
|
||||
|
|
|
@ -82,7 +82,7 @@ int main(int argc, char *argv[]) {
|
|||
if (IsWindows() && !IsAtLeastWindows10()) {
|
||||
plan(0x50000000, 0x7ffdffff, "arena");
|
||||
}
|
||||
x = (intptr_t)GetStaticStackAddr(0);
|
||||
x = GetStaticStackAddr(0);
|
||||
y = ROUNDUP(sizeof(struct WinArgs), FRAMESIZE);
|
||||
plan(x - y, x - 1, "winargs");
|
||||
plan(x, x + GetStackSize() - 1, "stack");
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue