mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Release Cosmopolitan v3.0
This commit is contained in:
parent
8f82a5f968
commit
4ae5223eae
4 changed files with 43 additions and 26 deletions
|
@ -186,7 +186,7 @@ compile. The only exception is the C preprocessor mode, which actually
|
||||||
runs x86-64 GCC except with macros like `__x86_64__` undefined.
|
runs x86-64 GCC except with macros like `__x86_64__` undefined.
|
||||||
|
|
||||||
This toolchain works great for C projects that are written in a portable
|
This toolchain works great for C projects that are written in a portable
|
||||||
way and don't produce architecturue-specific artifacts. One example of a
|
way and don't produce architecture-specific artifacts. One example of a
|
||||||
large project that can be easily built is GNU coreutils.
|
large project that can be easily built is GNU coreutils.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
|
@ -421,8 +421,8 @@ header file. If you're doing your development work on Linux or BSD then
|
||||||
you need just five files to get started. Here's what you do on Linux:
|
you need just five files to get started. Here's what you do on Linux:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-2.2.zip
|
wget https://justine.lol/cosmopolitan/cosmopolitan-amalgamation-3.0.zip
|
||||||
unzip cosmopolitan-amalgamation-2.2.zip
|
unzip cosmopolitan-amalgamation-3.0.zip
|
||||||
printf 'main() { printf("hello world\\n"); }\n' >hello.c
|
printf 'main() { printf("hello world\\n"); }\n' >hello.c
|
||||||
gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \
|
gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \
|
||||||
-fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs -gdwarf-4 \
|
-fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs -gdwarf-4 \
|
||||||
|
|
|
@ -73,6 +73,7 @@
|
||||||
"Cache-Control: private; max-age=0\r\n"
|
"Cache-Control: private; max-age=0\r\n"
|
||||||
|
|
||||||
int server;
|
int server;
|
||||||
|
int threads;
|
||||||
atomic_int a_termsig;
|
atomic_int a_termsig;
|
||||||
atomic_int a_workers;
|
atomic_int a_workers;
|
||||||
atomic_int a_messages;
|
atomic_int a_messages;
|
||||||
|
@ -102,6 +103,14 @@ void SomethingImportantHappened(void) {
|
||||||
unassert(!pthread_mutex_unlock(&statuslock));
|
unassert(!pthread_mutex_unlock(&statuslock));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wontreturn void ExplainPrlimit(void) {
|
||||||
|
kprintf("error: you need more resources; try running:\n"
|
||||||
|
"sudo prlimit --pid=$$ --nofile=%d\n"
|
||||||
|
"sudo prlimit --pid=$$ --nproc=%d\n",
|
||||||
|
threads * 2, threads * 2);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
void *Worker(void *id) {
|
void *Worker(void *id) {
|
||||||
pthread_setname_np(pthread_self(), "Worker");
|
pthread_setname_np(pthread_self(), "Worker");
|
||||||
|
|
||||||
|
@ -111,7 +120,7 @@ void *Worker(void *id) {
|
||||||
uint32_t clientsize;
|
uint32_t clientsize;
|
||||||
int inmsglen, outmsglen;
|
int inmsglen, outmsglen;
|
||||||
struct sockaddr_in clientaddr;
|
struct sockaddr_in clientaddr;
|
||||||
char inbuf[1500], outbuf[1500], *p, *q;
|
char buf[1000], *p, *q;
|
||||||
|
|
||||||
// musl libc and cosmopolitan libc support a posix thread extension
|
// musl libc and cosmopolitan libc support a posix thread extension
|
||||||
// that makes thread cancelation work much better. your io routines
|
// that makes thread cancelation work much better. your io routines
|
||||||
|
@ -131,6 +140,7 @@ void *Worker(void *id) {
|
||||||
// accept() errors are generally ephemeral or recoverable
|
// accept() errors are generally ephemeral or recoverable
|
||||||
// it'd potentially be a good idea to exponential backoff here
|
// it'd potentially be a good idea to exponential backoff here
|
||||||
if (errno == ECANCELED) continue; // pthread_cancel() was called
|
if (errno == ECANCELED) continue; // pthread_cancel() was called
|
||||||
|
if (errno == EMFILE) ExplainPrlimit();
|
||||||
LOG("accept() returned %m");
|
LOG("accept() returned %m");
|
||||||
SomethingHappened();
|
SomethingHappened();
|
||||||
continue;
|
continue;
|
||||||
|
@ -156,7 +166,7 @@ void *Worker(void *id) {
|
||||||
|
|
||||||
// wait for next http message (non-fragmented required)
|
// wait for next http message (non-fragmented required)
|
||||||
unassert(!pthread_setcancelstate(PTHREAD_CANCEL_MASKED, 0));
|
unassert(!pthread_setcancelstate(PTHREAD_CANCEL_MASKED, 0));
|
||||||
got = read(client, inbuf, sizeof(inbuf));
|
got = read(client, buf, sizeof(buf));
|
||||||
unassert(!pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0));
|
unassert(!pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0));
|
||||||
if (got <= 0) {
|
if (got <= 0) {
|
||||||
if (!got) {
|
if (!got) {
|
||||||
|
@ -174,7 +184,7 @@ void *Worker(void *id) {
|
||||||
|
|
||||||
// check that client message wasn't fragmented into more reads
|
// check that client message wasn't fragmented into more reads
|
||||||
InitHttpMessage(&msg, kHttpRequest);
|
InitHttpMessage(&msg, kHttpRequest);
|
||||||
if ((inmsglen = ParseHttpMessage(&msg, inbuf, got)) <= 0) {
|
if ((inmsglen = ParseHttpMessage(&msg, buf, got)) <= 0) {
|
||||||
if (!inmsglen) {
|
if (!inmsglen) {
|
||||||
LOG("%6H client sent fragmented message");
|
LOG("%6H client sent fragmented message");
|
||||||
} else {
|
} else {
|
||||||
|
@ -188,7 +198,7 @@ void *Worker(void *id) {
|
||||||
++a_messages;
|
++a_messages;
|
||||||
LOG("%6H received message from %hhu.%hhu.%hhu.%hhu:%hu for path %#.*s",
|
LOG("%6H received message from %hhu.%hhu.%hhu.%hhu:%hu for path %#.*s",
|
||||||
clientip >> 24, clientip >> 16, clientip >> 8, clientip,
|
clientip >> 24, clientip >> 16, clientip >> 8, clientip,
|
||||||
ntohs(clientaddr.sin_port), msg.uri.b - msg.uri.a, inbuf + msg.uri.a);
|
ntohs(clientaddr.sin_port), msg.uri.b - msg.uri.a, buf + msg.uri.a);
|
||||||
SomethingHappened();
|
SomethingHappened();
|
||||||
|
|
||||||
// display hello world html page for http://127.0.0.1:8080/
|
// display hello world html page for http://127.0.0.1:8080/
|
||||||
|
@ -196,13 +206,13 @@ void *Worker(void *id) {
|
||||||
int64_t unixts;
|
int64_t unixts;
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
if (msg.method == kHttpGet &&
|
if (msg.method == kHttpGet &&
|
||||||
(msg.uri.b - msg.uri.a == 1 && inbuf[msg.uri.a + 0] == '/')) {
|
(msg.uri.b - msg.uri.a == 1 && buf[msg.uri.a + 0] == '/')) {
|
||||||
q = "<!doctype html>\r\n"
|
q = "<!doctype html>\r\n"
|
||||||
"<title>hello world</title>\r\n"
|
"<title>hello world</title>\r\n"
|
||||||
"<h1>hello world</h1>\r\n"
|
"<h1>hello world</h1>\r\n"
|
||||||
"<p>this is a fun webpage\r\n"
|
"<p>this is a fun webpage\r\n"
|
||||||
"<p>hosted by greenbean\r\n";
|
"<p>hosted by greenbean\r\n";
|
||||||
p = stpcpy(outbuf, "HTTP/1.1 200 OK\r\n" STANDARD_RESPONSE_HEADERS
|
p = stpcpy(buf, "HTTP/1.1 200 OK\r\n" STANDARD_RESPONSE_HEADERS
|
||||||
"Content-Type: text/html; charset=utf-8\r\n"
|
"Content-Type: text/html; charset=utf-8\r\n"
|
||||||
"Date: ");
|
"Date: ");
|
||||||
clock_gettime(0, &ts), unixts = ts.tv_sec;
|
clock_gettime(0, &ts), unixts = ts.tv_sec;
|
||||||
|
@ -211,16 +221,15 @@ void *Worker(void *id) {
|
||||||
p = FormatInt32(p, strlen(q));
|
p = FormatInt32(p, strlen(q));
|
||||||
p = stpcpy(p, "\r\n\r\n");
|
p = stpcpy(p, "\r\n\r\n");
|
||||||
p = stpcpy(p, q);
|
p = stpcpy(p, q);
|
||||||
outmsglen = p - outbuf;
|
outmsglen = p - buf;
|
||||||
sent = write(client, outbuf, outmsglen);
|
sent = write(client, buf, outmsglen);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// display 404 not found error page for every thing else
|
// display 404 not found error page for every thing else
|
||||||
q = "<!doctype html>\r\n"
|
q = "<!doctype html>\r\n"
|
||||||
"<title>404 not found</title>\r\n"
|
"<title>404 not found</title>\r\n"
|
||||||
"<h1>404 not found</h1>\r\n";
|
"<h1>404 not found</h1>\r\n";
|
||||||
p = stpcpy(outbuf,
|
p = stpcpy(buf, "HTTP/1.1 404 Not Found\r\n" STANDARD_RESPONSE_HEADERS
|
||||||
"HTTP/1.1 404 Not Found\r\n" STANDARD_RESPONSE_HEADERS
|
|
||||||
"Content-Type: text/html; charset=utf-8\r\n"
|
"Content-Type: text/html; charset=utf-8\r\n"
|
||||||
"Date: ");
|
"Date: ");
|
||||||
clock_gettime(0, &ts), unixts = ts.tv_sec;
|
clock_gettime(0, &ts), unixts = ts.tv_sec;
|
||||||
|
@ -229,8 +238,8 @@ void *Worker(void *id) {
|
||||||
p = FormatInt32(p, strlen(q));
|
p = FormatInt32(p, strlen(q));
|
||||||
p = stpcpy(p, "\r\n\r\n");
|
p = stpcpy(p, "\r\n\r\n");
|
||||||
p = stpcpy(p, q);
|
p = stpcpy(p, q);
|
||||||
outmsglen = p - outbuf;
|
outmsglen = p - buf;
|
||||||
sent = write(client, outbuf, p - outbuf);
|
sent = write(client, buf, p - buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the client isn't pipelining and write() wrote the full
|
// if the client isn't pipelining and write() wrote the full
|
||||||
|
@ -283,7 +292,7 @@ int main(int argc, char *argv[]) {
|
||||||
unassert(!sigaction(SIGTERM, &sa, 0));
|
unassert(!sigaction(SIGTERM, &sa, 0));
|
||||||
|
|
||||||
// you can pass the number of threads you want as the first command arg
|
// you can pass the number of threads you want as the first command arg
|
||||||
int threads = argc > 1 ? atoi(argv[1]) : __get_cpu_count();
|
threads = argc > 1 ? atoi(argv[1]) : __get_cpu_count();
|
||||||
if (!(1 <= threads && threads <= 100000)) {
|
if (!(1 <= threads && threads <= 100000)) {
|
||||||
tinyprint(2, "error: invalid number of threads\n", NULL);
|
tinyprint(2, "error: invalid number of threads\n", NULL);
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -372,10 +381,7 @@ int main(int argc, char *argv[]) {
|
||||||
if ((rc = pthread_create(th + i, &attr, Worker, (void *)(intptr_t)i))) {
|
if ((rc = pthread_create(th + i, &attr, Worker, (void *)(intptr_t)i))) {
|
||||||
--a_workers;
|
--a_workers;
|
||||||
kprintf("pthread_create failed: %s\n", strerror(rc));
|
kprintf("pthread_create failed: %s\n", strerror(rc));
|
||||||
if (rc == EAGAIN) {
|
if (rc == EAGAIN) ExplainPrlimit();
|
||||||
kprintf("sudo prlimit --pid=$$ --nofile=%d\n", threads * 2);
|
|
||||||
kprintf("sudo prlimit --pid=$$ --nproc=%d\n", threads * 2);
|
|
||||||
}
|
|
||||||
if (!i) exit(1);
|
if (!i) exit(1);
|
||||||
threads = i;
|
threads = i;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -47,6 +47,12 @@
|
||||||
#define CTL_HW 6
|
#define CTL_HW 6
|
||||||
#define HW_MACHINE 1
|
#define HW_MACHINE 1
|
||||||
|
|
||||||
|
#define COSMOPOLITAN_VERSION_STR__(x, y, z) #x "." #y "." #z
|
||||||
|
#define COSMOPOLITAN_VERSION_STR_(x, y, z) COSMOPOLITAN_VERSION_STR__(x, y, z)
|
||||||
|
#define COSMOPOLITAN_VERSION_STR \
|
||||||
|
COSMOPOLITAN_VERSION_STR_(__COSMOPOLITAN_MAJOR__, __COSMOPOLITAN_MINOR__, \
|
||||||
|
__COSMOPOLITAN_PATCH__)
|
||||||
|
|
||||||
// Gets BSD sysctl() string, guaranteeing NUL-terminator.
|
// Gets BSD sysctl() string, guaranteeing NUL-terminator.
|
||||||
// We ignore errors since this syscall mutates on ENOMEM.
|
// We ignore errors since this syscall mutates on ENOMEM.
|
||||||
// In that case, sysctl() doesn't guarantee the nul term.
|
// In that case, sysctl() doesn't guarantee the nul term.
|
||||||
|
@ -175,7 +181,7 @@ int uname(struct utsname *uts) {
|
||||||
}
|
}
|
||||||
if (!rc) {
|
if (!rc) {
|
||||||
char buf[SYS_NMLN];
|
char buf[SYS_NMLN];
|
||||||
stpcpy(buf, "Cosmopolitan 3.0-alpha");
|
stpcpy(buf, "Cosmopolitan " COSMOPOLITAN_VERSION_STR);
|
||||||
if (*MODE) {
|
if (*MODE) {
|
||||||
strlcat(buf, " MODE=" MODE, SYS_NMLN);
|
strlcat(buf, " MODE=" MODE, SYS_NMLN);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,9 @@
|
||||||
#define __COSMOPOLITAN__ 1
|
#define __COSMOPOLITAN_MAJOR__ 3
|
||||||
|
#define __COSMOPOLITAN_MINOR__ 0
|
||||||
|
#define __COSMOPOLITAN_PATCH__ 0
|
||||||
|
#define __COSMOPOLITAN__ \
|
||||||
|
(100000000 * __COSMOPOLITAN_MAJOR__ + 1000000 * __COSMOPOLITAN_MINOR__ + \
|
||||||
|
__COSMOPOLITAN_PATCH__)
|
||||||
|
|
||||||
#ifndef __COUNTER__
|
#ifndef __COUNTER__
|
||||||
#define __COUNTER__ __LINE__
|
#define __COUNTER__ __LINE__
|
||||||
|
|
Loading…
Reference in a new issue