feat: cleanup and daemonization
This commit is contained in:
parent
dcc25f88a7
commit
1bcdca9e21
10
Makefile
10
Makefile
@ -2,26 +2,20 @@
|
|||||||
# See LICENSE file for copyright and license details.
|
# See LICENSE file for copyright and license details.
|
||||||
# Note: If you're confused by the makefile, I do emplore you to read the info-page: $ info make
|
# Note: If you're confused by the makefile, I do emplore you to read the info-page: $ info make
|
||||||
.POSIX:
|
.POSIX:
|
||||||
|
|
||||||
NAME=sci
|
NAME=sci
|
||||||
DESCRIPTION=$(NAME) is a simple contiuous integration system.
|
DESCRIPTION=$(NAME) is a simple contiuous integration system.
|
||||||
VERSION = 0.1.0
|
VERSION = 0.1.0
|
||||||
|
|
||||||
CC = gcc
|
CC = gcc
|
||||||
OUTDIR := out/
|
OUTDIR := out/
|
||||||
OBJDIR := out/obj
|
OBJDIR := out/obj
|
||||||
BINDIR := out/bin
|
BINDIR := out/bin
|
||||||
# defs
|
|
||||||
CFLAGS += -DSCI_VERSION="\"$(VERSION)\""
|
CFLAGS += -DSCI_VERSION="\"$(VERSION)\""
|
||||||
CFLAGS += -DSCI_NAME="\"$(NAME)\""
|
CFLAGS += -DSCI_NAME="\"$(NAME)\""
|
||||||
CFLAGS += -DSCI_DESCRIPTION="\"$(DESCRIPTION)\""
|
CFLAGS += -DSCI_DESCRIPTION="\"$(DESCRIPTION)\""
|
||||||
CFLAGS += -D_POSIX_C_SOURCE=2
|
CFLAGS += -D_POSIX_C_SOURCE=2
|
||||||
CFLAGS += -D_GNU_SOURCE
|
CFLAGS += -D_GNU_SOURCE
|
||||||
# compiler flags
|
|
||||||
CFLAGS += -Wall -Werror -std=c23 -g
|
CFLAGS += -Wall -Werror -std=c23 -g
|
||||||
# includes
|
|
||||||
CFLAGS += -Iinclude
|
CFLAGS += -Iinclude
|
||||||
# libraries
|
|
||||||
CFLAGS += -lpthread
|
CFLAGS += -lpthread
|
||||||
|
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
@ -71,7 +65,3 @@ $(BINDIR): $(OUTDIR)
|
|||||||
# chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1
|
# chmod 644 $(DESTDIR)$(MANPREFIX)/man1/st.1
|
||||||
# tic -sx st.info
|
# tic -sx st.info
|
||||||
# @echo Please see the README file regarding the terminfo entry of st.
|
# @echo Please see the README file regarding the terminfo entry of st.
|
||||||
#
|
|
||||||
# uninstall:
|
|
||||||
# rm -f $(DESTDIR)$(PREFIX)/bin/st
|
|
||||||
# rm -f $(DESTDIR)$(MANPREFIX)/man1/st.1
|
|
||||||
|
17
README.md
17
README.md
@ -84,9 +84,20 @@ If you want `compile_commands.json` files, you should use [bear](https://github.
|
|||||||
- [x] Third things third, implement a thing that simultaneously watches two different files (multithreading).
|
- [x] Third things third, implement a thing that simultaneously watches two different files (multithreading).
|
||||||
it should be cancellable with ctrl+c, but it should just contiuously print event notifications.
|
it should be cancellable with ctrl+c, but it should just contiuously print event notifications.
|
||||||
- [x] Fourth things fourth, implement a prototype that reads a space-separated file and populates a struct.
|
- [x] Fourth things fourth, implement a prototype that reads a space-separated file and populates a struct.
|
||||||
- [ ] Fifth things fifth, implement a prototype that spawns a new thread that executes a shell command.
|
- [x] Fifth things fifth, implement a prototype that spawns a new thread that executes a shell command.
|
||||||
- [ ] Voila! You're there!
|
- [ ] Sixth things sixth, daemonize it!
|
||||||
- [ ] Second iteration! Now Reimplement it and do it better!
|
- [ ] Seventh things seventh, package the sucker (arch, debian, alpine, docker)
|
||||||
|
- [ ] Eight things eight, try it out! - maybe even write the python webhook extension.
|
||||||
|
- [ ] Ninth things ninth, fix bugs, see below
|
||||||
|
- [ ] Tenth things tenth, write manpages
|
||||||
|
- [ ] Eleventh things last, release!
|
||||||
|
|
||||||
|
#### Bugs
|
||||||
|
- [ ] command output is being inherited. It should be piped into some random log-file
|
||||||
|
- [ ] pretty sure that `ctrl+c` / SIGINT is not graceful yet.
|
||||||
|
- [ ] missing license
|
||||||
|
- [ ] I am deliberately not using `Restart=on-failure` in the `scid.service` file because we are using `Type=exec`
|
||||||
|
and not `Type=notify` (yet) - which would require a `sd_notify` call of `READY=1` (see `man systemd.service`)
|
||||||
|
|
||||||
### Note Regarding `inotify` usage
|
### Note Regarding `inotify` usage
|
||||||
From the manpage:
|
From the manpage:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#ifndef SCI_CLI_H
|
#ifndef SCI_CLI_H
|
||||||
#define SCI_CLI_H
|
#define SCI_CLI_H
|
||||||
#include <stdio.h>
|
|
||||||
#include "optional.h"
|
#include "optional.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
optional_str config_file;
|
optional_str config_file;
|
||||||
|
@ -1,9 +1,7 @@
|
|||||||
#ifndef SCI_LOG_H
|
#ifndef SCI_LOG_H
|
||||||
#define SCI_LOG_H
|
#define SCI_LOG_H
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
// TODO: Thread safety!
|
|
||||||
enum {
|
enum {
|
||||||
LOG_TRACE = 4,
|
LOG_TRACE = 4,
|
||||||
LOG_INFO = 3,
|
LOG_INFO = 3,
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#define SCI_PIPELINE_H
|
#define SCI_PIPELINE_H
|
||||||
#include "optional.h"
|
#include "optional.h"
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <sys/inotify.h>
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char* name;
|
char* name;
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
#ifndef SCI_THREADPOOL_H
|
#ifndef SCI_THREADPOOL_H
|
||||||
#define SCI_THREADPOOL_H
|
#define SCI_THREADPOOL_H
|
||||||
#include <stdbool.h>
|
#include "optional.h"
|
||||||
#include <stddef.h>
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
// Very inspired by: https://nachtimwald.com/2019/04/12/thread-pool-in-c/
|
#include <stdbool.h>
|
||||||
|
|
||||||
// a work function
|
// a work function
|
||||||
typedef void (*thread_func)(void *arg);
|
typedef void (*thread_func)(void *arg);
|
||||||
@ -14,6 +13,7 @@ typedef struct threadpool_work {
|
|||||||
void* arg;
|
void* arg;
|
||||||
struct threadpool_work* next;
|
struct threadpool_work* next;
|
||||||
} threadpool_work;
|
} threadpool_work;
|
||||||
|
typedef optional_type(threadpool_work*) optional_threadpool_work;
|
||||||
|
|
||||||
// thread pool object
|
// thread pool object
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
10
scid.service
Normal file
10
scid.service
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Simple Continuous Integration Service
|
||||||
|
AssertPathExists=/etc/sci/pipelines.conf
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=exec
|
||||||
|
ExecStart=/usr/local/bin/sci
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
@ -1,8 +1,7 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include <stdbool.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <time.h>
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
pthread_mutex_t log_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
log_settings g_log_settings;
|
log_settings g_log_settings;
|
||||||
|
16
src/main.c
16
src/main.c
@ -4,14 +4,8 @@
|
|||||||
#include "pipeline.h"
|
#include "pipeline.h"
|
||||||
#include "threadpool.h"
|
#include "threadpool.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include <bits/pthreadtypes.h>
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <regex.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
void executor(void* data) {
|
void executor(void* data) {
|
||||||
const char* command = data;
|
const char* command = data;
|
||||||
@ -21,7 +15,8 @@ void executor(void* data) {
|
|||||||
threadpool* pool = NULL;
|
threadpool* pool = NULL;
|
||||||
|
|
||||||
void on_event(pipeline_event* const e) {
|
void on_event(pipeline_event* const e) {
|
||||||
threadpool_add_work(pool, executor, (void*)e->command);
|
if(!threadpool_add_work(pool, executor, (void*)e->command))
|
||||||
|
log_error("could not add work to the threadpool");
|
||||||
}
|
}
|
||||||
|
|
||||||
void* listen_for_changes_thread(void* data) {
|
void* listen_for_changes_thread(void* data) {
|
||||||
@ -74,7 +69,6 @@ int main(int argc, char** argv) {
|
|||||||
settings.use_colors = args.use_colors;
|
settings.use_colors = args.use_colors;
|
||||||
settings.out_file = args.log_file.has_value ? fopen(args.log_file.value, "w+") : stdout;
|
settings.out_file = args.log_file.has_value ? fopen(args.log_file.value, "w+") : stdout;
|
||||||
log_init(settings);
|
log_init(settings);
|
||||||
pool = threadpool_create(args.executors);
|
|
||||||
|
|
||||||
if(args.help) {
|
if(args.help) {
|
||||||
print_help(stdout, argv[0]);
|
print_help(stdout, argv[0]);
|
||||||
@ -100,8 +94,14 @@ int main(int argc, char** argv) {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pool = threadpool_create(args.executors);
|
||||||
per_line(args.config_file.value, &config_interpret_line);
|
per_line(args.config_file.value, &config_interpret_line);
|
||||||
|
|
||||||
|
// BOOKMARK: You were reading :Man system.unit and :Man systemd.service as preperation on making a systemd unit file
|
||||||
|
// This will be needed for the .deb package, as well as the arch linux package.
|
||||||
|
// alpine linux is using OpenRC (cool), which complicates things a little bit, but shouldn't be too bad. The wiki is
|
||||||
|
// generally really well written. Otherwise, I am sure that both wiki.gentoo and wiki.archlinux have great pages too
|
||||||
|
// docker is super easy, just make a dockerfile - only concern is the trigger files.
|
||||||
pipeline_loop();
|
pipeline_loop();
|
||||||
threadpool_destroy(pool);
|
threadpool_destroy(pool);
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
#include "pipeline.h"
|
#include "pipeline.h"
|
||||||
#include "threadlist.h"
|
#include "threadlist.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include <assert.h>
|
|
||||||
#include <regex.h>
|
#include <regex.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
#include "threadpool.h"
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "threadpool.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
static threadpool_work* threadpool_work_create(thread_func func, void *arg) {
|
static optional_threadpool_work threadpool_work_create(thread_func func, void *arg) {
|
||||||
threadpool_work* result;
|
optional_threadpool_work result;
|
||||||
if (func == NULL)
|
result.value = NULL;
|
||||||
return NULL;
|
result.has_value = false;
|
||||||
result = malloc(sizeof(threadpool_work));
|
if(func == NULL) {
|
||||||
result->func = func;
|
log_error("cant create threadpool work, function is null");
|
||||||
result->arg = arg;
|
return result;
|
||||||
result->next = NULL;
|
}
|
||||||
|
result.value = malloc(sizeof(threadpool_work));
|
||||||
|
result.value->func = func;
|
||||||
|
result.value->arg = arg;
|
||||||
|
result.value->next = NULL;
|
||||||
|
result.has_value = true;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +96,6 @@ threadpool* threadpool_create(size_t num) {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
// TODO: add log statements
|
|
||||||
|
|
||||||
void threadpool_destroy(threadpool* pool) {
|
void threadpool_destroy(threadpool* pool) {
|
||||||
log_trace("destroying threadpool");
|
log_trace("destroying threadpool");
|
||||||
@ -122,21 +126,24 @@ void threadpool_destroy(threadpool* pool) {
|
|||||||
|
|
||||||
bool threadpool_add_work(threadpool* pool, thread_func func, void *arg) {
|
bool threadpool_add_work(threadpool* pool, thread_func func, void *arg) {
|
||||||
log_trace("adding work task to pool");
|
log_trace("adding work task to pool");
|
||||||
threadpool_work* work;
|
if(pool == NULL) {
|
||||||
if (pool == NULL)
|
log_error("could not add work to threadpool, pool is null");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
work = threadpool_work_create(func, arg);
|
optional_threadpool_work work = threadpool_work_create(func, arg);
|
||||||
if (work == NULL)
|
if(!work.has_value) {
|
||||||
|
log_error("could not add work to threadpool");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&(pool->work_mutex));
|
pthread_mutex_lock(&(pool->work_mutex));
|
||||||
if (pool->work_first == NULL) {
|
if (pool->work_first == NULL) {
|
||||||
pool->work_first = work;
|
pool->work_first = work.value;
|
||||||
pool->work_last = pool->work_first;
|
pool->work_last = pool->work_first;
|
||||||
} else {
|
} else {
|
||||||
pool->work_last->next = work;
|
pool->work_last->next = work.value;
|
||||||
pool->work_last = work;
|
pool->work_last = work.value;
|
||||||
}
|
}
|
||||||
pthread_cond_broadcast(&(pool->work_cond));
|
pthread_cond_broadcast(&(pool->work_cond));
|
||||||
pthread_mutex_unlock(&(pool->work_mutex));
|
pthread_mutex_unlock(&(pool->work_mutex));
|
||||||
@ -145,8 +152,10 @@ bool threadpool_add_work(threadpool* pool, thread_func func, void *arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void threadpool_wait(threadpool* pool) {
|
void threadpool_wait(threadpool* pool) {
|
||||||
if (pool == NULL)
|
if(pool == NULL) {
|
||||||
|
log_error("pool object is null");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
pthread_mutex_lock(&(pool->work_mutex));
|
pthread_mutex_lock(&(pool->work_mutex));
|
||||||
while (1) {
|
while (1) {
|
||||||
if (pool->work_first != NULL || (!pool->stop && pool->working_count != 0) || (pool->stop && pool->thread_count != 0))
|
if (pool->work_first != NULL || (!pool->stop && pool->working_count != 0) || (pool->stop && pool->thread_count != 0))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user