Dmitry Yu Okunev лет назад: 8
Сommit
f635b01241
13 измененных файлов с 1327 добавлено и 0 удалено
  1. 2 0
      .gitignore
  2. 66 0
      GNUmakefile
  3. 43 0
      binary.c
  4. 26 0
      binary.h
  5. 28 0
      configuration.h
  6. 380 0
      error.c
  7. 79 0
      error.h
  8. 45 0
      macros.h
  9. 272 0
      main.c
  10. 243 0
      malloc.c
  11. 39 0
      malloc.h
  12. 77 0
      pthreadex.c
  13. 27 0
      pthreadex.h

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+*.o
+voltlogger_oscilloscope

+ 66 - 0
GNUmakefile

@@ -0,0 +1,66 @@
+
+DESTDIR ?= 
+PREFIX  ?= /usr
+COMPRESS_MAN ?= yes
+STRIP_BINARY ?= yes
+EXAMPLES ?= yes
+
+CSECFLAGS ?= -fstack-protector-all -Wall --param ssp-buffer-size=4 -D_FORTIFY_SOURCE=2 -fstack-check -DPARANOID -std=gnu99
+CFLAGS ?= -pipe -O2
+CFLAGS += $(CSECFLAGS) $(shell pkg-config --cflags gtk+-2.0) -flto
+DEBUGCFLAGS ?= -pipe -Wall -Werror -ggdb3 -export-dynamic -Wno-error=unused-variable -O0 -pipe $(CSECFLAGS)
+
+CARCHFLAGS ?= -march=native
+
+LIBS := -lm $(shell pkg-config --libs gtk+-2.0)
+LDSECFLAGS ?= -Xlinker -zrelro
+LDFLAGS += $(LDSECFLAGS) -pthread -flto
+INC := $(INC)
+
+INSTDIR = $(DESTDIR)$(PREFIX)
+
+objs=\
+pthreadex.o\
+binary.o\
+error.o\
+malloc.o\
+main.o\
+
+
+binary=voltlogger_oscilloscope
+
+.PHONY: doc
+
+all: $(objs)
+	$(CC) $(CARCHFLAGS) $(CFLAGS) $(LDFLAGS) $(objs) $(LIBS) -o $(binary)
+
+%.o: %.c
+	$(CC) $(CARCHFLAGS) $(CFLAGS) $(INC) $< -c -o $@
+
+debug:
+	$(CC) $(CARCHFLAGS) -D_DEBUG_SUPPORT $(DEBUGCFLAGS) $(INC) $(LDFLAGS) *.c $(LIBS) -o $(binary)
+
+
+clean:
+	rm -f $(binary) *.o
+
+distclean: clean
+
+doc:
+	doxygen .doxygen
+
+install:
+	install -d "$(INSTDIR)/bin" "$(INSTDIR)/share/man/man1"
+ifeq ($(STRIP_BINARY),yes)
+	strip --strip-unneeded -R .comment -R .GCC.command.line -R .note.gnu.gold-version $(binary)
+endif
+	install -m 755 $(binary) "$(INSTDIR)"/bin/
+	install -m 644 man/man1/voltlogger_oscilloscope.1 "$(INSTDIR)"/share/man/man1/
+ifeq ($(COMPRESS_MAN),yes)
+	rm -f "$(INSTDIR)"/share/man/man1/voltlogger_oscilloscope.1.gz
+	gzip "$(INSTDIR)"/share/man/man1/voltlogger_oscilloscope.1
+endif
+
+deinstall:
+	rm -f "$(INSTDIR)"/bin/$(binary)
+

+ 43 - 0
binary.c

@@ -0,0 +1,43 @@
+/*
+    voltlogger_oscilloscope
+    
+    Copyright (C) 2015 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
+    
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+    
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <assert.h>	/* assert()	*/
+#include <unistd.h>
+
+#include "binary.h"
+
+
+#define DECLARE_GET_X_t(x) 				\
+	x ## _t get_ ## x (FILE *i_f) {		\
+		x ## _t r;				\
+							\
+		if (fread(&r, sizeof(r), 1, i_f) < 1) {	\
+			if (feof(i_f)) sleep(3600*24*30);	\
+			assert (ferror(i_f));		\
+		}					\
+							\
+		return r;				\
+	}
+
+DECLARE_GET_X_t(uint64);
+DECLARE_GET_X_t(uint32);
+DECLARE_GET_X_t(uint16);
+//DECLARE_GET_X_t(uint8);
+

+ 26 - 0
binary.h

@@ -0,0 +1,26 @@
+/*
+    voltlogger_oscilloscope
+    
+    Copyright (C) 2015 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
+    
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+    
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ 
+*/
+#include <stdio.h>	/* FILE		*/
+#include <stdint.h>	/* uint64_t	*/
+
+extern uint64_t get_uint64(FILE *i_f);
+extern uint32_t get_uint32(FILE *i_f);
+extern uint16_t get_uint16(FILE *i_f);
+

+ 28 - 0
configuration.h

@@ -0,0 +1,28 @@
+/*
+    voltlogger_oscilloscope
+    
+    Copyright (C) 2015 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
+    
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+    
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#define	SYSLOG_BUFSIZ			4096
+#define	SYSLOG_FLAGS			LOG_PID
+#define	SYSLOG_FACILITY			LOG_INFO
+
+#define	OUTPUT_LOCK_TIMEOUT		1000
+
+#define PARSER_MAXELEMENTS		65536
+

+ 380 - 0
error.c

@@ -0,0 +1,380 @@
+/*
+    voltlogger_oscilloscope
+    
+    Copyright (C) 2015 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
+    
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+    
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * This file implements way to output debugging information. It's supposed
+ * to be slow but convenient functions.
+ */
+
+#include "configuration.h"
+
+#include <stdlib.h>
+#include <execinfo.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include <pthread.h>	/* pthread_self() */
+#include <sys/types.h>	/* getpid() */
+#include <unistd.h>	/* getpid() */
+
+#include "error.h"
+#include "pthreadex.h"
+
+static int zero     = 0;
+static int three    = 3;
+
+static int *outputmethod = &zero;
+static int *debug	 = &zero;
+static int *quiet	 = &zero;
+static int *verbose	 = &three;
+
+pthread_mutex_t *error_mutex_p = NULL;
+
+static int printf_stderr(const char *fmt, ...) {
+	va_list args;
+	int rc;
+
+	va_start(args, fmt);
+	rc = vfprintf(stderr, fmt, args);
+	va_end(args);
+
+	return rc;
+}
+
+static int printf_stdout(const char *fmt, ...) {
+	va_list args;
+	int rc;
+
+	va_start(args, fmt);
+	rc = vfprintf(stdout, fmt, args);
+	va_end(args);
+
+	return rc;
+}
+
+static int vprintf_stderr(const char *fmt, va_list args) {
+	return vfprintf(stderr, fmt, args);
+}
+
+static int vprintf_stdout(const char *fmt, va_list args) {
+	return vfprintf(stdout, fmt, args);
+}
+
+
+static void flush_stderr(int level) {
+	fprintf(stderr, "\n");
+	fflush(stderr);
+}
+
+static void flush_stdout(int level) {
+	fprintf(stdout, "\n");
+	fflush(stdout);
+}
+
+
+static char _syslog_buffer[SYSLOG_BUFSIZ+1] = {0};
+size_t      _syslog_buffer_filled = 0;
+
+static int vsyslog_buf(const char *fmt, va_list args) {
+	int len;
+	size_t size;
+
+	size = SYSLOG_BUFSIZ - _syslog_buffer_filled;
+
+#ifdef VERYPARANOID
+	if (
+		(			 size	> SYSLOG_BUFSIZ)	|| 
+		(_syslog_buffer_filled + size	> SYSLOG_BUFSIZ)	||
+		(_syslog_buffer_filled		> SYSLOG_BUFSIZ)
+	) {
+		fprintf(stderr, "Security problem while vsyslog_buf(): "
+			"_syslog_buffer_filled == %lu; "
+			"size == %lu; "
+			"SYSLOG_BUFSIZ == "XTOSTR(SYSLOG_BUFSIZ)"\n",
+			_syslog_buffer_filled, size);
+		exit(ENOBUFS);
+	}
+#endif
+	if (!size)
+		return 0;
+
+	len = vsnprintf (
+		&_syslog_buffer[_syslog_buffer_filled],
+		size,
+		fmt,
+		args
+	);
+
+	if (len>0) {
+		_syslog_buffer_filled += len;
+		if (_syslog_buffer_filled > SYSLOG_BUFSIZ)
+			_syslog_buffer_filled = SYSLOG_BUFSIZ;
+	}
+
+	return 0;
+}
+
+static int syslog_buf(const char *fmt, ...) {
+	va_list args;
+	int rc;
+
+	va_start(args, fmt);
+	rc = vsyslog_buf(fmt, args);
+	va_end(args);
+
+	return rc;
+}
+
+static void syslog_flush(int level) {
+	syslog(level, "%s", _syslog_buffer);
+	_syslog_buffer_filled = 0;
+}
+
+typedef int  *(  *outfunct_t)(const char *format, ...);
+typedef int  *( *voutfunct_t)(const char *format, va_list ap);
+typedef void *(*flushfunct_t)(int level);
+
+static outfunct_t outfunct[] = {
+	[OM_STDERR]	= (outfunct_t)printf_stderr,
+	[OM_STDOUT]	= (outfunct_t)printf_stdout,
+	[OM_SYSLOG]	= (outfunct_t)syslog_buf,
+};
+
+static voutfunct_t voutfunct[] = {
+	[OM_STDERR]	= (voutfunct_t)vprintf_stderr,
+	[OM_STDOUT]	= (voutfunct_t)vprintf_stdout,
+	[OM_SYSLOG]	= (voutfunct_t)vsyslog_buf,
+};
+
+static flushfunct_t flushfunct[] = {
+	[OM_STDERR]	= (flushfunct_t)flush_stderr,
+	[OM_STDOUT]	= (flushfunct_t)flush_stdout,
+	[OM_SYSLOG]	= (flushfunct_t)syslog_flush,
+};
+
+void _critical(const char *const function_name, const char *fmt, ...) {
+	if (*quiet)
+		return;
+
+	struct timespec abs_time;
+	clock_gettime(CLOCK_REALTIME , &abs_time);
+	abs_time.tv_sec += 1;
+
+	if (error_mutex_p != NULL)
+		pthread_mutex_timedlock(error_mutex_p, &abs_time);
+
+	outputmethod_t method = *outputmethod;
+
+	{
+		va_list args;
+		pthread_t thread = pthread_self();
+		pid_t pid = getpid();
+
+		outfunct[method]("Critical (pid: %u; thread: %p): %s(): ", pid, thread, function_name);
+		va_start(args, fmt);
+		voutfunct[method](fmt, args);
+		va_end(args);
+		outfunct[method](" (current errno %i: %s)", errno, strerror(errno));
+		flushfunct[method](LOG_CRIT);
+	}
+
+#ifdef BACKTRACE_SUPPORT
+	{
+		void  *buf[BACKTRACE_LENGTH];
+		char **strings;
+		int backtrace_len = backtrace((void **)buf, BACKTRACE_LENGTH);
+
+		strings = backtrace_symbols(buf, backtrace_len);
+		if (strings == NULL) {
+			outfunct[method]("_critical(): Got error, but cannot print the backtrace. Current errno: %u: %s\n",
+				errno, strerror(errno));
+			flushfunct[method](LOG_CRIT);
+			pthread_mutex_unlock(error_mutex_p);
+			exit(EXIT_FAILURE);
+		}
+
+		for (int j = 1; j < backtrace_len; j++) {
+			outfunct[method]("        %s", strings[j]);
+			flushfunct[method](LOG_CRIT);
+		}
+	}
+#endif
+
+	if (error_mutex_p != NULL)
+		pthread_mutex_unlock(error_mutex_p);
+
+	error_deinit();
+	exit(errno);
+
+	return;
+}
+
+void _error(const char *const function_name, const char *fmt, ...) {
+	va_list args;
+
+	if (*quiet)
+		return;
+
+	if (*verbose < 1)
+		return;
+
+	if (error_mutex_p != NULL)
+		pthread_mutex_reltimedlock(error_mutex_p, 0, OUTPUT_LOCK_TIMEOUT);
+
+	pthread_t thread = pthread_self();
+	pid_t pid = getpid();
+	outputmethod_t method = *outputmethod;
+
+	outfunct[method](*debug ? "Error (pid: %u; thread: %p): %s(): " : "Error: ", pid, thread, function_name);
+	va_start(args, fmt);
+	voutfunct[method](fmt, args);
+	va_end(args);
+	if (errno)
+		outfunct[method](" (%i: %s)", errno, strerror(errno));
+	flushfunct[method](LOG_ERR);
+
+	if (error_mutex_p != NULL)
+		pthread_mutex_unlock(error_mutex_p);
+	return;
+}
+
+void _info(const char *const function_name, const char *fmt, ...) {
+	va_list args;
+
+	if (*quiet)
+		return;
+
+	if (*verbose < 3)
+		return;
+
+	if (error_mutex_p != NULL)
+		pthread_mutex_reltimedlock(error_mutex_p, 0, OUTPUT_LOCK_TIMEOUT);
+
+	pthread_t thread = pthread_self();
+	pid_t pid = getpid();
+	outputmethod_t method = *outputmethod;
+
+	outfunct[method](*debug ? "Info (pid: %u; thread: %p): %s(): " : "Info: ", pid, thread, function_name);
+	va_start(args, fmt);
+	voutfunct[method](fmt, args);
+	va_end(args);
+	flushfunct[method](LOG_INFO);
+
+	if (error_mutex_p != NULL)
+		pthread_mutex_unlock(error_mutex_p);
+	return;
+}
+
+void _warning(const char *const function_name, const char *fmt, ...) {
+	va_list args;
+
+	if (*quiet)
+		return;
+
+	if (*verbose < 2)
+		return;
+
+	if (error_mutex_p != NULL)
+		pthread_mutex_reltimedlock(error_mutex_p, 0, OUTPUT_LOCK_TIMEOUT);
+
+	pthread_t thread = pthread_self();
+	pid_t pid = getpid();
+	outputmethod_t method = *outputmethod;
+
+	outfunct[method](*debug ? "Warning (pid: %u; thread: %p): %s(): " : "Warning: ", pid, thread, function_name);
+	va_start(args, fmt);
+	voutfunct[method](fmt, args);
+	va_end(args);
+	flushfunct[method](LOG_WARNING);
+
+	if (error_mutex_p != NULL)
+		pthread_mutex_unlock(error_mutex_p);
+	return;
+}
+
+#ifdef _DEBUG_SUPPORT
+void _debug(int debug_level, const char *const function_name, const char *fmt, ...) {
+	va_list args;
+
+	if (*quiet)
+		return;
+
+	if (debug_level > *debug)
+		return;
+
+	if (error_mutex_p != NULL)
+		pthread_mutex_reltimedlock(error_mutex_p, 0, OUTPUT_LOCK_TIMEOUT);
+
+	pthread_t thread = pthread_self();
+	pid_t pid = getpid();
+	outputmethod_t method = *outputmethod;
+
+	outfunct[method]("Debug%u (pid: %u; thread: %p): %s(): ", debug_level, pid, thread, function_name);
+	va_start(args, fmt);
+	voutfunct[method](fmt, args);
+	va_end(args);
+	flushfunct[method](LOG_DEBUG);
+
+	if (error_mutex_p != NULL)
+		pthread_mutex_unlock(error_mutex_p);
+	return;
+}
+#endif
+
+void error_init(void *_outputmethod, int *_quiet, int *_verbose, int *_debug) {
+	outputmethod 	= _outputmethod;
+	quiet		= _quiet;
+	verbose		= _verbose;
+	debug		= _debug;
+
+	openlog(NULL, SYSLOG_FLAGS, SYSLOG_FACILITY);
+
+	return;
+}
+
+ipc_type_t ipc_type;
+void error_init_ipc(ipc_type_t _ipc_type) {
+	static pthread_mutex_t error_mutex = PTHREAD_MUTEX_INITIALIZER;
+	ipc_type = _ipc_type;
+
+	switch (ipc_type) {
+		case IPCT_PRIVATE:
+			error_mutex_p = &error_mutex;
+			pthread_mutex_init(error_mutex_p, NULL);
+			break;
+		default:
+			critical ("Unknown ipc_type: %i", ipc_type);
+	}
+
+	return;
+}
+
+void error_deinit() {
+	switch (ipc_type) {
+		case IPCT_PRIVATE:
+			break;
+		default:
+			critical ("Unknown ipc_type: %i", ipc_type);
+	}
+
+	return;
+}
+

+ 79 - 0
error.h

@@ -0,0 +1,79 @@
+/*
+    voltlogger_oscilloscope
+    
+    Copyright (C) 2015 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
+    
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+    
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __CLSYNC_ERROR_H
+#define __CLSYNC_ERROR_H
+
+#define BACKTRACE_LENGTH	256
+
+#ifdef _DEBUG_FORCE
+#	define DEBUGLEVEL_LIMIT 255
+#else
+#	define DEBUGLEVEL_LIMIT 9
+#endif
+
+extern void _critical( const char *const function_name, const char *fmt, ...);
+#define critical(...) 				_critical(__FUNCTION__, __VA_ARGS__)
+#define critical_on(cond) {debug(30, "critical_on: checking: %s", TOSTR(cond)); if (unlikely(cond)) {critical("Assert: "TOSTR(cond));}}
+
+extern void _error(const char *const function_name, const char *fmt, ...);
+#define error(...) 				_error(__FUNCTION__, __VA_ARGS__)
+#define error_on(cond)	  {if (unlikely(cond)) {error("Error: ("TOSTR(cond)") != 0");}}
+
+extern void _warning(const char *const function_name, const char *fmt, ...);
+#define warning(...) 				_warning(__FUNCTION__, __VA_ARGS__)
+
+extern void _info(const char *const function_name, const char *fmt, ...);
+#define info(...) 				_info(__FUNCTION__, __VA_ARGS__)
+
+#ifdef _DEBUG_SUPPORT
+	extern void _debug(int debug_level, const char *const function_name, const char *fmt, ...);
+#	define debug(debug_level, ...)			{if (debug_level < DEBUGLEVEL_LIMIT) _debug(debug_level, __FUNCTION__, __VA_ARGS__);}
+#	define error_or_debug(debug_level, ...)		((debug_level)<0 ? _error(__FUNCTION__, __VA_ARGS__) : _debug(debug_level, __FUNCTION__, __VA_ARGS__))
+#else
+#	define debug(debug_level, ...)			{}
+#	define error_or_debug(debug_level, ...)		((debug_level)<0 ? _error(__FUNCTION__, __VA_ARGS__) : (void)0)
+
+#endif
+
+#define debug_call(debug_level, code)			debug(debug_level, "%s -> %i", TOSTR(code), code)
+
+#define critical_or_warning(cond, ...) ((cond) ? _critical : _warning)(__FUNCTION__, __VA_ARGS__)
+
+enum ipc_type {
+	IPCT_PRIVATE,
+	IPCT_SHARED,
+};
+typedef enum ipc_type ipc_type_t;
+
+extern void error_init(void *_outputmethod, int *_quiet, int *_verbose, int *_debug);
+extern void error_init_ipc(ipc_type_t ipc_type);
+extern void error_deinit();
+
+enum outputmethod {
+	OM_STDERR = 0,
+	OM_STDOUT,
+	OM_SYSLOG,
+
+	OM_MAX
+};
+typedef enum outputmethod outputmethod_t;
+
+#endif
+

+ 45 - 0
macros.h

@@ -0,0 +1,45 @@
+/*
+    voltlogger_oscilloscope
+    
+    Copyright (C) 2015 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
+    
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+    
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef _GNU_SOURCE
+#	ifndef likely
+#		define likely(x)    __builtin_expect(!!(x), 1)
+#	endif
+#	ifndef unlikely
+#		define unlikely(x)  __builtin_expect(!!(x), 0)
+#	endif
+#else
+#	ifndef likely
+#		define likely(x)   (x)
+#	endif
+#	ifndef unlikely
+#		define unlikely(x) (x)
+#	endif
+#endif
+
+#define TOSTR(a) # a
+#define XTOSTR(a) TOSTR(a)
+
+#define MAX(a, b) (((a)>(b)) ? (a) : (b))
+#define MIN(a, b) (((a)<(b)) ? (a) : (b))
+
+#define STDIN		0
+#define STDOUT		1
+#define STDERR		2
+

+ 272 - 0
main.c

@@ -0,0 +1,272 @@
+/*
+    voltlogger_oscilloscope
+    
+    Copyright (C) 2015 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
+    
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+    
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ 
+*/
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>	/* free()	*/
+#include <string.h>
+#include <unistd.h>
+//#include <fcntl.h>
+#include <gtk/gtk.h>
+#include <pthread.h>
+
+#include "binary.h"
+#include "malloc.h"
+
+FILE *sensor;
+FILE *dump;
+
+#define HISTORY_SIZE (1 << 20)
+#define MAX_CHANNELS 1
+#define Y_BITS 12
+
+typedef struct {
+	uint64_t timestamp;
+	uint32_t value;
+} history_t;
+
+int running = 1;
+
+history_t  *history       [MAX_CHANNELS];
+uint32_t    history_length[MAX_CHANNELS] = {0};
+uint64_t    ts_global = 0;
+
+pthread_mutex_t history_mutex;
+
+double x_userdiv    = 1E-3;
+double x_useroffset = 0;
+double y_userscale  = 14;
+double y_useroffset = -0.11;
+
+void
+sensor_open()
+{
+	sensor = stdin;
+
+	return;
+}
+
+int
+sensor_fetch(history_t *p)
+{
+	uint16_t ts_local;
+	uint16_t ts_local_old;
+	uint16_t value;
+
+	ts_local = get_uint16(sensor);
+	value    = get_uint16(sensor);
+
+	ts_local_old = ts_global & 0xffff;
+	if (ts_local <= ts_local_old) {
+		ts_global += 1<<16;
+	}
+
+	ts_global = (ts_global & ~0xffff) | ts_local;
+
+	p->timestamp = ts_global;
+	p->value     = value;
+
+	return 1;
+}
+
+void
+sensor_close()
+{
+	return;
+}
+
+void
+dump_open()
+{
+	dump = stdin;
+
+	return;
+}
+
+int
+dump_fetch(history_t *p)
+{
+	uint64_t ts_parse;
+	uint64_t ts_device;
+	uint32_t value;
+
+	ts_parse  = get_uint64(dump);
+	ts_device = get_uint64(dump);
+	value     = get_uint32(dump);
+
+	(void)ts_parse;
+	p->timestamp = ts_device;
+	p->value     = value;
+
+	return 1;
+}
+
+void
+dump_close()
+{
+	return;
+}
+
+void
+history_flush()
+{
+	//sleep(3600);
+	pthread_mutex_lock(&history_mutex);
+	memcpy(history[0], &history[0][HISTORY_SIZE], sizeof(*history[0])*HISTORY_SIZE);
+	history_length[0] = HISTORY_SIZE;
+
+	printf("history_flush()\n");
+	pthread_mutex_unlock(&history_mutex);
+	return;
+}
+
+void *
+history_fetcher(void *arg)
+{
+	while (running) {
+		//sensor_fetch(&history[0][ history_length[0]++ ]);
+		dump_fetch(&history[0][ history_length[0]++ ]);
+//		printf("%lu; %u\n", history[0][ history_length[0]-1].timestamp, history[0][ history_length[0]-1].value);
+		if (history_length[0] >= HISTORY_SIZE * 2) 
+			history_flush();
+	}
+
+	return NULL;
+}
+
+static gboolean
+cb_expose (GtkWidget      *area,
+           GdkEventExpose *event,
+           gpointer       *data)
+{
+	int width, height;
+	cairo_t *cr;
+
+	cr	= gdk_cairo_create (event->window);
+	width	= gdk_window_get_width (event->window);
+	height	= gdk_window_get_height (event->window);
+
+	cairo_rectangle(cr, 0, 0, width, height);
+	cairo_set_source_rgb(cr, 1, 1, 1);
+	cairo_fill(cr);
+
+	cairo_set_line_width (cr, 2);
+
+	int history_end   = history_length[0]-2;
+
+	if (history_end >= HISTORY_SIZE) {
+		printf("%u %u\n", HISTORY_SIZE, history_end);
+		pthread_mutex_lock(&history_mutex);
+		cairo_set_source_rgba (cr, 0, 0, 0.3, 0.8);
+		cairo_move_to(cr, -1, height/2);
+		int x;//, x_old = -1;
+		int y;//, y_old =  0;
+
+		//int history_start = history_end - HISTORY_SIZE;
+		int history_start = history_end - (double)HISTORY_SIZE*x_userdiv;
+		uint64_t timestamp_start = history[0][history_start].timestamp;
+		uint64_t timestamp_end   = history[0][history_end  ].timestamp;
+		
+		int history_cur = history_start;
+
+		if (timestamp_start == timestamp_end) {
+			printf("%lu %lu %u %u %u %u\n", timestamp_start, timestamp_end, history_start, history_end, history[0][history_start].value, history[0][history_end].value);
+		}
+		assert (timestamp_end != timestamp_start);
+
+		double x_scale = (double)width  / (timestamp_end - timestamp_start);
+		double y_scale = (double)height / (1 << Y_BITS);
+
+		while (history_cur < history_end) {
+			history_t *p = &history[0][ history_cur++ ];
+
+			x = (double)x_useroffset*width              + (double)x_scale               * (double)(p->timestamp - timestamp_start);
+			y = (double)height/2 + (double)y_useroffset*y_userscale*height + (double)y_scale * y_userscale * (double) p->value;
+			cairo_line_to(cr, x, y);
+			//printf("xy: %u (%lu %e) %u (%u %e %e)\n", x, p->timestamp - timestamp_start, x_scale, y, p->value, y_scale, y_userscale);
+		}
+		cairo_stroke(cr);
+		pthread_mutex_unlock(&history_mutex);
+	}
+
+	cairo_set_source_rgba (cr, 0, 0, 0, 0.2);
+	cairo_move_to(cr, 0,	 height/2);
+	cairo_line_to(cr, width, height/2);
+	cairo_stroke(cr);
+
+	cairo_destroy (cr);
+	return TRUE;
+}
+
+int
+main (int    argc,
+      char **argv)
+{
+	int i;
+	pthread_t thread_fetcher;
+	//sensor_open();
+	i = 0;
+	while (i < MAX_CHANNELS)
+		history[i++] = xcalloc(HISTORY_SIZE * 2 + 1, sizeof(history_t));
+	dump_open();
+
+	if (pthread_create(&thread_fetcher, NULL, history_fetcher, NULL)) {
+		fprintf(stderr, "Error creating thread\n");
+		return 1;
+	}
+
+	GtkWidget *main_window,
+	          *vbox,
+	          *button,
+	          *area;
+
+	gtk_init (&argc, &argv);
+	main_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_default_size (GTK_WINDOW (main_window), 800, 600);
+	g_signal_connect (main_window, "destroy", gtk_main_quit, NULL);
+	vbox = gtk_vbox_new (FALSE, 5);
+	gtk_container_add (GTK_CONTAINER (main_window), vbox);
+	button = gtk_button_new_from_stock (GTK_STOCK_REFRESH);
+	gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+	area = gtk_drawing_area_new ();
+	g_signal_connect (area, "expose-event", G_CALLBACK (cb_expose), NULL);
+	gtk_box_pack_start (GTK_BOX (vbox), area, TRUE, TRUE, 0);
+	g_signal_connect_swapped (button, "clicked",
+	                          G_CALLBACK (gtk_widget_queue_draw), area);
+	gtk_widget_show_all (main_window);
+
+	gtk_main ();
+
+	running = 0;
+
+	if (pthread_join(thread_fetcher, NULL)) {
+		fprintf(stderr, "Error joining thread\n");
+		return 2;
+	}
+
+//	sensor_close();
+	dump_close();
+	i = 0;
+	while (i < MAX_CHANNELS)
+		free(history[i++]);
+	return 0;
+}
+

+ 243 - 0
malloc.c

@@ -0,0 +1,243 @@
+/*
+    voltlogger_oscilloscope
+
+    Copyright (C) 2015  Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "macros.h"
+#include "configuration.h"
+
+#include <stdlib.h>
+#include <string.h>
+#ifdef CAPABILITIES_SUPPORT
+# include <unistd.h>
+# include <sys/mman.h>
+# ifdef SECCOMP_SUPPORT
+#  include <sys/stat.h>
+#  include <fcntl.h>
+# endif
+#endif
+
+#include <sys/ipc.h>			// shmget()
+#include <sys/shm.h>			// shmget()
+
+#include "malloc.h"
+#include "error.h"
+#include "configuration.h"
+
+#ifdef CAPABILITIES_SUPPORT
+long pagesize;
+# ifdef SECCOMP_SUPPORT
+int  devzero_fd;
+# endif
+#endif
+
+void *xmalloc(size_t size) {
+	debug(20, "(%li)", size);
+#ifdef PARANOID
+	size++;	// Just in case
+#endif
+
+	void *ret = malloc(size);
+
+	if (ret == NULL)
+		critical("(%li): Cannot allocate memory.", size);
+
+#ifdef PARANOID
+	memset(ret, 0, size);
+#endif
+	return ret;
+}
+
+void *xcalloc(size_t nmemb, size_t size) {
+	debug(20, "(%li, %li)", nmemb, size);
+#ifdef PARANOID
+	nmemb++; // Just in case
+	size++;	 // Just in case
+#endif
+
+	void *ret = calloc(nmemb, size);
+
+	if (ret == NULL)
+		critical("(%li): Cannot allocate memory.", size);
+
+//	memset(ret, 0, nmemb*size);	// Just in case
+	return ret;
+}
+
+void *xrealloc(void *oldptr, size_t size) {
+	debug(20, "(%p, %li)", oldptr, size);
+#ifdef PARANOID
+	size++;	// Just in case
+#endif
+
+	void *ret = realloc(oldptr, size);
+
+	if (ret == NULL)
+		critical("(%p, %li): Cannot reallocate memory.", oldptr, size);
+
+	return ret;
+}
+
+#ifdef CAPABILITIES_SUPPORT
+void *malloc_align(size_t size) {
+	size_t total_size;
+	void *ret = NULL;
+	debug(20, "(%li)", size);
+# ifdef PARANOID
+	size++;	 // Just in case
+# endif
+
+	total_size  = size;
+# ifdef PARANOID
+	total_size += pagesize-1;
+	total_size /= pagesize;
+	total_size *= pagesize;
+# endif
+
+	if (posix_memalign(&ret, pagesize, total_size))
+		critical("(%li): Cannot allocate memory.", size);
+
+# ifdef PARANOID
+	if (ret == NULL)
+		critical("(%li): ptr == NULL.", size);
+# endif
+
+//	memset(ret, 0, nmemb*size);	// Just in case
+	return ret;
+}
+
+void *calloc_align(size_t nmemb, size_t size) {
+	size_t total_size;
+	void *ret;
+	debug(20, "(%li, %li)", nmemb, size);
+# ifdef PARANOID
+	nmemb++; // Just in case
+	size++;	 // Just in case
+# endif
+
+	total_size = nmemb*size;
+	ret = malloc_align(total_size);
+	memset(ret, 0, total_size);
+
+	return ret;
+}
+
+char *strdup_protect(const char *src, int prot) {
+	size_t len = strlen(src);
+	char *dst  = malloc_align(len);
+	strcpy(dst, src);
+	if (mprotect(dst, len, prot))
+		critical("(%p, 0x%o): Got error from mprotect(%p, %lu, 0x%o)", src, prot, dst, len, prot);
+
+	return dst;
+}
+
+# ifdef SECCOMP_SUPPORT
+int is_protected(void *addr) {
+	char *_addr = addr, t;
+	int is_protected;
+	t = *_addr;
+
+	is_protected = (read(devzero_fd, addr, 1) == -1);
+
+	if (!is_protected)
+		*_addr = t;
+
+	return is_protected;
+}
+# endif
+
+#endif
+
+int memory_init() {
+#ifdef CAPABILITIES_SUPPORT
+	pagesize   = sysconf(_SC_PAGE_SIZE);
+
+	if (pagesize == -1)
+		critical("Got error from sysconf(_SC_PAGE_SIZE)");
+
+# ifdef SECCOMP_SUPPORT
+	devzero_fd = open(DEVZERO, O_RDONLY);
+
+	if (devzero_fd == -1)
+		critical("Got error while open(\""DEVZERO"\", O_RDONLY)");
+# endif
+#endif
+
+	return 0;
+}
+
+void *shm_malloc_try(size_t size) {
+	void *ret;
+#ifdef PARANOID
+	size++;
+#endif
+	int privileged_shmid = shmget(0, size, IPC_PRIVATE|IPC_CREAT|0600);
+	struct shmid_ds shmid_ds;
+	if (privileged_shmid == -1) return NULL;
+
+	ret = shmat(privileged_shmid, NULL, 0);
+	if ((long)ret == -1) return NULL;
+	debug(15, "ret == %p", ret);
+
+	// Forbidding access for others to the pointer
+	shmctl(privileged_shmid, IPC_STAT, &shmid_ds);
+	shmid_ds.shm_perm.mode = 0;
+	shmctl(privileged_shmid, IPC_SET,  &shmid_ds);
+
+	// Checking that nobody else attached to the shared memory before access forbidding
+	shmctl(privileged_shmid, IPC_STAT, &shmid_ds);
+	if (shmid_ds.shm_lpid != shmid_ds.shm_cpid) {
+		error("A process (pid %u) attached to my shared memory. It's a security problem. Emergency exit.");
+		shmdt (ret);
+		return NULL;
+	}
+
+	return ret;
+}
+
+void *shm_malloc(size_t size) {
+	void *ret;
+
+	ret = shm_malloc_try(size);
+	critical_on (ret == NULL);
+
+	return ret;
+}
+
+void *shm_calloc(size_t nmemb, size_t size) {
+	void *ret;
+	size_t total_size;
+#ifdef PARANOID
+	nmemb++;
+	size++;
+#endif
+
+	total_size = nmemb * size;
+
+	ret = shm_malloc(total_size);
+	critical_on (ret == NULL);
+
+	memset(ret, 0, total_size);
+	return ret;
+}
+
+void shm_free(void *ptr) {
+	debug(25, "(%p)", ptr);
+	shmdt(ptr);
+}
+

+ 39 - 0
malloc.h

@@ -0,0 +1,39 @@
+/*
+    voltlogger_oscilloscope
+
+    Copyright (C) 2015  Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <sys/types.h>
+
+extern void *xmalloc(size_t size);
+extern void *xcalloc(size_t nmemb, size_t size);
+extern void *xrealloc(void *oldptr, size_t size);
+#ifdef CAPABILITIES_SUPPORT
+extern void *malloc_align(size_t size);
+extern void *calloc_align(size_t nmemb, size_t size);
+extern char *strdup_protect(const char *src, int prot);
+# ifdef SECCOMP_SUPPORT
+extern int is_protected(void *addr);
+# endif
+#endif
+extern void *shm_malloc(size_t size);
+extern void *shm_malloc_try(size_t size);
+extern void *shm_calloc(size_t nmemb, size_t size);
+extern void shm_free(void *ptr);
+
+extern int memory_init();
+

+ 77 - 0
pthreadex.c

@@ -0,0 +1,77 @@
+/*
+    voltlogger_oscilloscope
+    
+    Copyright (C) 2015 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
+    
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+    
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <pthread.h>
+#include "pthreadex.h"
+#include "malloc.h"
+
+int pthread_mutex_init_shared(pthread_mutex_t **mutex_p) {
+	static pthread_mutex_t mutex_initial = PTHREAD_MUTEX_INITIALIZER;
+	*mutex_p = shm_malloc_try(sizeof(**mutex_p));
+	memcpy(*mutex_p, &mutex_initial, sizeof(mutex_initial));
+
+	pthread_mutexattr_t attr;
+	pthread_mutexattr_init(&attr);
+	pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
+	return pthread_mutex_init(*mutex_p, &attr);
+}
+
+int pthread_mutex_destroy_shared(pthread_mutex_t *mutex_p) {
+	int rc;
+	rc = pthread_mutex_destroy(mutex_p);
+	shm_free(mutex_p);
+	return rc;
+}
+
+int pthread_cond_init_shared(pthread_cond_t **cond_p) {
+	static pthread_cond_t cond_initial = PTHREAD_COND_INITIALIZER;
+	*cond_p = shm_malloc(sizeof(**cond_p));
+	memcpy(*cond_p, &cond_initial, sizeof(cond_initial));
+
+	pthread_condattr_t attr;
+	pthread_condattr_init(&attr);
+	pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
+	return pthread_cond_init(*cond_p, &attr);
+}
+
+int pthread_cond_destroy_shared(pthread_cond_t *cond_p) {
+	int rc;
+	rc = pthread_cond_destroy(cond_p);
+	shm_free(cond_p);
+	return rc;
+}
+
+int pthread_mutex_reltimedlock(pthread_mutex_t *mutex_p, long tv_sec, long tv_nsec) {
+	struct timespec abs_time;
+
+	if (clock_gettime(CLOCK_REALTIME, &abs_time))
+		return -1;
+
+	abs_time.tv_sec  += tv_sec;
+	abs_time.tv_nsec += tv_nsec;
+
+	if (abs_time.tv_nsec > 1000*1000*1000) {
+		abs_time.tv_sec++;
+		abs_time.tv_nsec -= 1000*1000*1000;
+	}
+
+	return pthread_mutex_timedlock(mutex_p, &abs_time);
+}
+

+ 27 - 0
pthreadex.h

@@ -0,0 +1,27 @@
+/*
+    voltlogger_oscilloscope
+    
+    Copyright (C) 2015 Dmitry Yu Okunev <dyokunev@ut.mephi.ru> 0x8E30679C
+    
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+    
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+    
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <pthread.h>
+
+extern int pthread_mutex_init_shared(pthread_mutex_t **mutex_p);
+extern int pthread_mutex_destroy_shared(pthread_mutex_t *mutex_p);
+extern int pthread_cond_init_shared(pthread_cond_t **cond_p);
+extern int pthread_cond_destroy_shared(pthread_cond_t *cond_p);
+extern int pthread_mutex_reltimedlock(pthread_mutex_t *mutex_p, long tv_sec, long tv_nsec);
+