aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile.am28
-rwxr-xr-xbuild-aux/valgrind.sh1
-rw-r--r--configure.ac6
-rw-r--r--src/blogc-runserver/httpd.c58
-rw-r--r--src/common/error.c3
-rw-r--r--src/common/error.h1
-rw-r--r--src/common/thread.h23
-rw-r--r--src/common/thread_pthread.c82
8 files changed, 189 insertions, 13 deletions
diff --git a/Makefile.am b/Makefile.am
index f33798d..f988199 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -69,6 +69,7 @@ noinst_HEADERS = \
src/common/error.h \
src/common/file.h \
src/common/stdin.h \
+ src/common/thread.h \
src/common/utf8.h \
src/common/utils.h \
$(NULL)
@@ -76,6 +77,7 @@ noinst_HEADERS = \
noinst_LTLIBRARIES = \
libblogc.la \
libblogc_common.la \
+ libblogc_common_thread.la \
$(NULL)
noinst_PROGRAMS = \
@@ -157,6 +159,31 @@ libblogc_common_la_CFLAGS = \
$(NULL)
+if BUILD_PTHREAD
+libblogc_common_thread_la_SOURCES = \
+ src/common/thread_pthread.c \
+ $(NULL)
+
+libblogc_common_thread_la_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(PTHREAD_CFLAGS) \
+ $(NULL)
+
+libblogc_common_thread_la_LIBADD = \
+ $(PTHREAD_LIBS) \
+ libblogc_common.la \
+ $(NULL)
+else
+libblogc_common_thread_la_SOURCES = \
+ src/common/thread_windows.c \
+ $(NULL)
+
+libblogc_common_thread_la_LIBADD = \
+ libblogc_common.la \
+ $(NULL)
+endif
+
+
blogc_SOURCES = \
src/blogc/main.c \
$(NULL)
@@ -271,6 +298,7 @@ blogc_runserver_LDADD = \
$(PTHREAD_LIBS) \
libblogc_runserver.la \
libblogc_common.la \
+ libblogc_common_thread.la \
$(NULL)
libblogc_runserver_la_SOURCES = \
diff --git a/build-aux/valgrind.sh b/build-aux/valgrind.sh
index 991b906..bdf7e70 100755
--- a/build-aux/valgrind.sh
+++ b/build-aux/valgrind.sh
@@ -4,6 +4,7 @@ export TESTS_ENVIRONMENT="
${VALGRIND:-valgrind} \
--tool=memcheck \
--leak-check=full \
+ --show-leak-kinds=all \
--leak-resolution=high \
--num-callers=20 \
--error-exitcode=1 \
diff --git a/configure.ac b/configure.ac
index 6ed9e3d..fc6c2ad 100644
--- a/configure.ac
+++ b/configure.ac
@@ -24,6 +24,12 @@ PKG_PROG_PKG_CONFIG
AC_PROG_SED
+have_pthread=no
+AX_PTHREAD([
+ have_pthread=yes
+])
+AM_CONDITIONAL([BUILD_PTHREAD], [test "x$have_pthread" = "xyes"])
+
RPM_VERSION=`echo ${PACKAGE_VERSION} | sed "s/-/./g"`
AC_SUBST(RPM_VERSION)
diff --git a/src/blogc-runserver/httpd.c b/src/blogc-runserver/httpd.c
index 6cbd198..1c27b3d 100644
--- a/src/blogc-runserver/httpd.c
+++ b/src/blogc-runserver/httpd.c
@@ -21,6 +21,7 @@
#include <pthread.h>
#include "../common/error.h"
#include "../common/file.h"
+#include "../common/thread.h"
#include "../common/utils.h"
#include "mime.h"
#include "httpd-utils.h"
@@ -28,7 +29,7 @@
#define LISTEN_BACKLOG 100
typedef struct {
- pthread_t thread;
+ bc_thread_t *thread;
bool initialized;
} thread_data_t;
@@ -212,9 +213,9 @@ point2:
point1:
fprintf(stderr, "[Thread-%zu] %s - - \"%s\" %d\n", thread_id + 1,
ip, conn_line, status_code);
- free(conn_line);
bc_strv_free(pieces);
point0:
+ free(conn_line);
free(ip);
close(client_socket);
return NULL;
@@ -257,7 +258,7 @@ int
br_httpd_run(const char *host, const char *port, const char *docroot,
size_t max_threads)
{
- int err;
+ int r;
struct addrinfo *result;
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
@@ -268,12 +269,14 @@ br_httpd_run(const char *host, const char *port, const char *docroot,
.ai_addr = NULL,
.ai_next = NULL,
};
- if (0 != (err = getaddrinfo(host, port, &hints, &result))) {
+ if (0 != (r = getaddrinfo(host, port, &hints, &result))) {
fprintf(stderr, "Failed to get host:port info: %s\n",
- gai_strerror(err));
+ gai_strerror(r));
return 3;
}
+ bc_error_t *err = NULL;
+
thread_data_t threads[max_threads];
for (size_t i = 0; i < max_threads; i++)
threads[i].initialized = false;
@@ -380,19 +383,36 @@ br_httpd_run(const char *host, const char *port, const char *docroot,
arg->docroot = docroot;
if (threads[current_thread].initialized) {
- if (pthread_join(threads[current_thread].thread, NULL) != 0) {
- fprintf(stderr, "Failed to join thread\n");
- free(arg->ip);
- free(arg);
+ bc_thread_join(threads[current_thread].thread, &err);
+ bc_thread_free(threads[current_thread].thread);
+ threads[current_thread].thread = NULL;
+ threads[current_thread].initialized = false;
+ if (err != NULL) {
+ bc_error_print(err, "blogc-runserver");
+ bc_error_free(err);
+ err = NULL;
+ if (arg != NULL) {
+ free(arg->ip);
+ free(arg);
+ }
rv = 3;
goto cleanup;
}
}
- if (pthread_create(&(threads[current_thread].thread), NULL,
- handle_request, arg) != 0)
- {
- fprintf(stderr, "Failed to create thread\n");
+ threads[current_thread].thread = bc_thread_create(handle_request, arg,
+ false, &err);
+ if (err != NULL) {
+ bc_error_print(err, "blogc-runserver");
+ bc_error_free(err);
+ err = NULL;
+ if (arg != NULL) {
+ free(arg->ip);
+ free(arg);
+ }
+ bc_thread_free(threads[current_thread].thread);
+ threads[current_thread].thread = NULL;
+ threads[current_thread].initialized = false;
rv = 3;
goto cleanup;
}
@@ -404,6 +424,18 @@ br_httpd_run(const char *host, const char *port, const char *docroot,
}
cleanup:
+ for (size_t i = 0; i < max_threads; i++) {
+ if (threads[i].initialized && threads[i].thread != NULL) {
+ bc_thread_join(threads[i].thread, &err);
+ bc_thread_free(threads[i].thread);
+ if (err != NULL) {
+ bc_error_free(err);
+ err = NULL;
+ rv = 3;
+ }
+ }
+ }
+
close(server_socket);
cleanup0:
diff --git a/src/common/error.c b/src/common/error.c
index 4538c01..a3a08e7 100644
--- a/src/common/error.c
+++ b/src/common/error.c
@@ -118,6 +118,9 @@ bc_error_print(bc_error_t *err, const char *prefix)
case BC_ERROR_FILE:
fprintf(stderr, "error: file: %s\n", err->msg);
break;
+ case BC_ERROR_THREAD:
+ fprintf(stderr, "error: thread: %s\n", err->msg);
+ break;
case BLOGC_ERROR_SOURCE_PARSER:
fprintf(stderr, "error: source: %s\n", err->msg);
break;
diff --git a/src/common/error.h b/src/common/error.h
index a567c6d..2aac439 100644
--- a/src/common/error.h
+++ b/src/common/error.h
@@ -17,6 +17,7 @@ typedef enum {
// errors for src/common
BC_ERROR_CONFIG_PARSER = 1,
BC_ERROR_FILE,
+ BC_ERROR_THREAD,
// errors for src/blogc
BLOGC_ERROR_SOURCE_PARSER = 100,
diff --git a/src/common/thread.h b/src/common/thread.h
new file mode 100644
index 0000000..850d375
--- /dev/null
+++ b/src/common/thread.h
@@ -0,0 +1,23 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2014-2018 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#ifndef _THREAD_H
+#define _THREAD_H
+
+#include <stdbool.h>
+
+typedef void* (*bc_thread_func_t) (void *arg);
+
+typedef struct _bc_thread_t bc_thread_t;
+
+bc_thread_t* bc_thread_create(bc_thread_func_t func, void *arg, bool detached,
+ bc_error_t **err);
+void bc_thread_join(bc_thread_t *thread, bc_error_t **err);
+void bc_thread_free(bc_thread_t *thread);
+
+#endif /* _THREAD_H */
diff --git a/src/common/thread_pthread.c b/src/common/thread_pthread.c
new file mode 100644
index 0000000..a85a0c7
--- /dev/null
+++ b/src/common/thread_pthread.c
@@ -0,0 +1,82 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2014-2018 Rafael G. Martins <rafael@rafaelmartins.eng.br>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#include <stdbool.h>
+#include <string.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include "error.h"
+#include "utils.h"
+#include "thread.h"
+
+struct _bc_thread_t {
+ pthread_t thread;
+};
+
+
+bc_thread_t*
+bc_thread_create(bc_thread_func_t func, void *arg, bool detached, bc_error_t **err)
+{
+ if (err == NULL || *err != NULL)
+ return NULL;
+
+ int r;
+
+ pthread_attr_t attr;
+ pthread_attr_t *attrp = NULL;
+
+ if (detached) {
+
+ if (0 != (r = pthread_attr_init(&attr))) {
+ *err = bc_error_new_printf(BC_ERROR_THREAD,
+ "Failed to initialize thread attributes: %s", strerror(r));
+ return NULL;
+ }
+
+ if (0 != (r = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))) {
+ *err = bc_error_new_printf(BC_ERROR_THREAD,
+ "Failed to mark thread as detached: %s", strerror(r));
+ return NULL;
+ }
+
+ attrp = &attr;
+ }
+
+ bc_thread_t *rv = bc_malloc(sizeof(bc_thread_t));
+
+ if (0 != (r = pthread_create(&(rv->thread), attrp, func, arg))) {
+ *err = bc_error_new_printf(BC_ERROR_THREAD,
+ "Failed to create thread: %s", strerror(r));
+ free(rv);
+ return NULL;
+ }
+
+ return rv;
+}
+
+
+void
+bc_thread_join(bc_thread_t *thread, bc_error_t **err)
+{
+ if (thread == NULL || err == NULL || *err != NULL)
+ return;
+
+ int r;
+
+ if (0 != (r = pthread_join(thread->thread, NULL))) {
+ *err = bc_error_new_printf(BC_ERROR_THREAD,
+ "Failed to join thread: %s", strerror(r));
+ }
+}
+
+
+void
+bc_thread_free(bc_thread_t *thread)
+{
+ free(thread);
+}