diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/modules/libscpp/bkup/scpp_assert.hpp b/modules/libscpp/bkup/scpp_assert.hpp new file mode 100644 index 0000000..094836e --- /dev/null +++ b/modules/libscpp/bkup/scpp_assert.hpp @@ -0,0 +1,29 @@ +/** + * @file scpp_assert.hpp + * @bried Assert モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include + +namespace scpp +{ + + +class AssertError : public std::exception +{ + public: + AssertError() noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string% msg, +}; + + +} + + +#endif // SCPP_ASSERT_HPP diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/modules/libscpp/bkup/scpp_assert.hpp b/modules/libscpp/bkup/scpp_assert.hpp new file mode 100644 index 0000000..094836e --- /dev/null +++ b/modules/libscpp/bkup/scpp_assert.hpp @@ -0,0 +1,29 @@ +/** + * @file scpp_assert.hpp + * @bried Assert モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include + +namespace scpp +{ + + +class AssertError : public std::exception +{ + public: + AssertError() noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string% msg, +}; + + +} + + +#endif // SCPP_ASSERT_HPP diff --git a/modules/libscpp/bkup/scpp_exception.cpp b/modules/libscpp/bkup/scpp_exception.cpp new file mode 100644 index 0000000..5ed0c1c --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.cpp @@ -0,0 +1,13 @@ +/** + * @file scpp_exception.cpp + * @bried Exception モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + + +namespace scpp +{ +} + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/modules/libscpp/bkup/scpp_assert.hpp b/modules/libscpp/bkup/scpp_assert.hpp new file mode 100644 index 0000000..094836e --- /dev/null +++ b/modules/libscpp/bkup/scpp_assert.hpp @@ -0,0 +1,29 @@ +/** + * @file scpp_assert.hpp + * @bried Assert モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include + +namespace scpp +{ + + +class AssertError : public std::exception +{ + public: + AssertError() noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string% msg, +}; + + +} + + +#endif // SCPP_ASSERT_HPP diff --git a/modules/libscpp/bkup/scpp_exception.cpp b/modules/libscpp/bkup/scpp_exception.cpp new file mode 100644 index 0000000..5ed0c1c --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.cpp @@ -0,0 +1,13 @@ +/** + * @file scpp_exception.cpp + * @bried Exception モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + + +namespace scpp +{ +} + diff --git a/modules/libscpp/bkup/scpp_exception.hpp b/modules/libscpp/bkup/scpp_exception.hpp new file mode 100644 index 0000000..b37132f --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.hpp @@ -0,0 +1,65 @@ +/** + * @file scpp_exception.hpp + * @bried Exception モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + +/** + * 例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ +class Throwable: public std::exception +{ + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(const std::string& msg) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; +}; + + +/** + * 回復可能な例外クラス。 + */ +class Exception : public Throwable +{ + public: + Exception() noexcept; + Exception(const Throwable& t) noexcept; + Exception(const std::string& msg) noexcept; + virtual ~Exception() noexcept; +}; + + +/** + * 回復困難な例外クラス。 + */ +class Error : public Throwable +{ + public: + Error() noexcept; + Error(const Throwable& t) noexcept; + Error(const std::string& msg) noexcept; + virtual ~Error() noexcept; +}; + + +} + + +#endif // SCPP_EXCEPTION_HPP diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/modules/libscpp/bkup/scpp_assert.hpp b/modules/libscpp/bkup/scpp_assert.hpp new file mode 100644 index 0000000..094836e --- /dev/null +++ b/modules/libscpp/bkup/scpp_assert.hpp @@ -0,0 +1,29 @@ +/** + * @file scpp_assert.hpp + * @bried Assert モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include + +namespace scpp +{ + + +class AssertError : public std::exception +{ + public: + AssertError() noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string% msg, +}; + + +} + + +#endif // SCPP_ASSERT_HPP diff --git a/modules/libscpp/bkup/scpp_exception.cpp b/modules/libscpp/bkup/scpp_exception.cpp new file mode 100644 index 0000000..5ed0c1c --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.cpp @@ -0,0 +1,13 @@ +/** + * @file scpp_exception.cpp + * @bried Exception モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + + +namespace scpp +{ +} + diff --git a/modules/libscpp/bkup/scpp_exception.hpp b/modules/libscpp/bkup/scpp_exception.hpp new file mode 100644 index 0000000..b37132f --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.hpp @@ -0,0 +1,65 @@ +/** + * @file scpp_exception.hpp + * @bried Exception モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + +/** + * 例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ +class Throwable: public std::exception +{ + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(const std::string& msg) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; +}; + + +/** + * 回復可能な例外クラス。 + */ +class Exception : public Throwable +{ + public: + Exception() noexcept; + Exception(const Throwable& t) noexcept; + Exception(const std::string& msg) noexcept; + virtual ~Exception() noexcept; +}; + + +/** + * 回復困難な例外クラス。 + */ +class Error : public Throwable +{ + public: + Error() noexcept; + Error(const Throwable& t) noexcept; + Error(const std::string& msg) noexcept; + virtual ~Error() noexcept; +}; + + +} + + +#endif // SCPP_EXCEPTION_HPP diff --git a/modules/libscpp/bkup/scpp_memory.cpp b/modules/libscpp/bkup/scpp_memory.cpp new file mode 100644 index 0000000..7213a9d --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.cpp @@ -0,0 +1,693 @@ +/** + * @file scpp_memory.cpp + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include +#include +#include +#include + + +// 本来の malloc, free を利用するため、ENABLED_MEMORY_MANAGE を無効にする +#ifdef ENABLED_MEMORY_MANAGE +#undef ENABLED_MEMORY_MANAGE +#endif +#include + + + +using namespace scpp; +namespace +{ + int const PADDING = sizeof(int) * 2; + int const MARK_ALLOCATED = 0x12340000; + int const MARK_ALLOCATED_NEW = 0x12341111; + int const MARK_ALLOCATED_NEW_ARRAY = 0x12342222; + int const MARK_DELETED = 0xFEDCBA00; + + bool infoIsInitialized = false; + std::mutex memMtx; //< 管理メモリ操作用 Mutex + MemoryInfo infoHead; //< 管理メモリ先頭 + MemoryInfo infoTail; //< 管理メモリ末尾 + MemoryInfo infoError; //< エラー発生時用 + MemoryListener* listener = 0; //< 通知リスナ + + // プロトタイプ宣言 + void init(); + void add(MemoryInfo* entry); + void remove(MemoryInfo* entry); + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func); + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng); + + /** + * new ハンドラを取得します。 + * + * @return new ハンドラ + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + /** + * メモリ管理初期化. + */ + void init() + { + if (!infoIsInitialized) + { + infoIsInitialized = true; + infoHead.fileName = infoTail.fileName = 0; + infoHead.lineNumber = infoTail.lineNumber = 0; + infoHead.functionName = infoTail.functionName = 0; + infoHead.size = infoTail.size = 0; + infoHead._prev = infoHead._next = &infoTail; + infoTail._prev = infoTail._next = &infoHead; + infoHead._mark = infoTail._mark = MARK_DELETED; + + // エラー処理用 + infoError.fileName = 0; + infoError.lineNumber = 0; + infoError.functionName = 0; + infoError.size = 0; + infoError._prev = 0; + infoError._next = 0; + infoError._mark = MARK_DELETED; + } + } + + + /** + * メモリエントリを追加します. + * + * @param entry 追加するエントリ + */ + void add(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + init(); + entry->_next = &infoTail; + entry->_prev = infoTail._prev; + infoTail._prev->_next = entry; + infoTail._prev = entry; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyAlloc(*entry); + } + } + + + /** + * メモリエントリを削除します. + * + * @param entry 削除するエントリ + */ + void remove(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyFree(*entry); + } + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func) + { + MemoryInfo* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast (::malloc(n + sizeof(MemoryInfo) + PADDING)); + if (entry != 0) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { + return 0; + } + } + + void* ptr = (entry + 1); + + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = ptr; + + // エントリに追加 + add(entry); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng) + { + if (isMng) + { // 管理メモリの場合, いったん削除 + remove(static_cast(ptr)); + } + + MemoryInfo* entry = static_cast (::realloc(ptr, n + sizeof(MemoryInfo) + PADDING)); + if (entry == 0) + { + // メモリ確保失敗 -> 元の領域は開放されないので再管理する + add(static_cast(ptr)); + errno = ENOMEM; + if (listener) + { // エラーハンドラが登録されている + infoError.size = n; + infoError.fileName = file; + infoError.lineNumber = line; + infoError.functionName = func; + listener->notifyError(infoError, "can't realloc"); + } + return 0; + } + + if (!isMng) + { // 管理対象外メモリの場合 + // |<---- 新たな確保領域 ---->| + // +----------+---------------+ + // |元々の領域|追加分+管理領域| + // +----------+---------------+ + // ↓ + // +--------+----------+------+ + // |管理領域|元々の領域|追加分| + // +--------+----------+------+ + memmove((entry + 1), entry, n); + } + + // 管理領域に情報を書き込む + void* nptr = (entry + 1); + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = nptr; + + // エントリに追加 + add(entry); + return nptr; + } + +} // namespace 無名 + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 以下, new / delete のオーバライド +// + + +void* operator new(std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new[](std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + +void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + + +void operator delete(void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } +} + +void operator delete(void* p, std::size_t) noexcept +{ + operator delete(p); +} + +void operator delete(void* p, const std::nothrow_t&) noexcept +{ + operator delete(p); +} + +void operator delete[](void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + +} + +void operator delete[](void* p, std::size_t) noexcept +{ + operator delete[](p); +} + +void operator delete[](void* p, const std::nothrow_t&) noexcept +{ + operator delete[](p); +} + + +namespace scpp +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// デフォルトのメモリ確保/開放時に実行されるリスナ +// + +DefaultMemoryListener::DefaultMemoryListener() +{ + // NOP +} +DefaultMemoryListener::~DefaultMemoryListener() +{ + // NOP +} + +/** + * メモリが確保された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyAlloc(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリが開放された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyFree(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリの確保/開放でエラーが発生した際に実行されるリスナ. + * エラー内容をエラー出力します. + * + * @param info メモリ情報 + * @param msg メッセージ + */ +void DefaultMemoryListener::notifyError(const MemoryInfo& info, const std::string& msg) +{ + std::cerr << "MemoryError: " << msg << std::endl; + std::cerr << "\tat " << info.fileName << ":" << info.lineNumber << ":" << info.functionName + << " (size = " << info.size << ")" << std::endl; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理 +// + +/** + * メモリ管理. + * メモリの確保, 開放を行います. + * リスナを登録することで, メモリ確保, 開放, エラー発生時の通知を + * 受信することができます. + * + * 以下のようにメモリを管理しています. + * @code + * + * |<----管理メモリ------------->| + * +--------+--------------------+ + * |管理領域|ユーザ使用メモリ領域| + * +--------+--------------------+ + * ↑ユーザにはこの位置を返す + * + * c++ なので std::list 等を使っても良いが, + * list のメモリ確保でエラーがでると本末転倒なので, + * メモリ確保時に管理領域をまとめて確保&管理する. + * @endcode + * + */ +namespace MemoryManager +{ + + thread_local const char* fileName = ""; // 名前一時保存用 + thread_local int lineNumber = 0; // 行番号一時保存用 + thread_local const char* functionName = ""; // 関数名一時保存用 + + /** + * メモリの確保,開放,エラー発生の通知を受信するリスナを登録します. + * + * @param l リスナ + */ + void setListener(MemoryListener* l) + { + listener = l; + } + + + /** + * 管理している全メモリエントリを引数に指定されたハンドラを実行します. + * デフォルトで用意しているハンドラ printMemoryInfo を使用できます. + * + * @param handler ハンドラ + */ + void entries(void (*handler)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + handler(*info); + info = info->_next; + } + } + + + /** + * 指定されたメソッドが true を返す管理メモリをクリア(削除)します. + * 本メソッド実行時, 管理しているメモリの情報を引数に + * 指定された関数が実行されます. + * + * [注意事項] + * 本メソッドでメモリはクリアしますが, デストラクタは呼び出されないので注意 + * + * 使用例) + * @code + * bool isCleanup(const scpp::MemoryInfo& info) + * { // 管理しているメモリ全てクリアする + * return true; + * } + * scpp::MemoryManager::cleanup(&isCleanup); + * @endcode + * + * @param isCleanup クリアするか否かを返す関数ポインタ + */ + void cleanup(bool (*isCleanup)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + bool ret = isCleanup(*info); + if (ret) + { // クリア対象 + MemoryInfo* tmpInfo; + tmpInfo = info; + info = info->_next; + remove(tmpInfo); + tmpInfo->size = 0; + tmpInfo->_mark = MARK_DELETED; + free(tmpInfo); + } + else + { + info = info->_next; + } + } + } + + + /** + * 指定されたメモリの情報を出力します. + * + * @param info メモリの情報 + */ + void printMemoryInfo(const MemoryInfo& info) + { + std::cout << "[MemoryInfo] " + << info.fileName << ":" + << info.lineNumber << ":" + << info.functionName << " (size = " + << info.size << ")" + << std::endl; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル名 + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, int line, const char* func) + { + void* ptr = allocate(size, MARK_ALLOCATED, file, line, func); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param nmemb 確保するメモリの要素数 + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func) + { + std::size_t n = nmemb * size; + void* ptr = allocate(n, MARK_ALLOCATED, file, line, func); + if (ptr) + { // callc なのでゼロクリアする + memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * ポインタが示すメモリブロックのサイズを変更します. + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func) + { + if (ptr == 0) + { // ptr が null の場合, malloc と等価 + ptr = malloc(size, file, line, func); + return ptr; + } + + if (size == 0) + { // size が 0 の場合, free と等価 + free(ptr); + return 0; + } + + // メモリ管理領域を取得 + MemoryInfo* entry = static_cast (ptr); + entry--; + void* nptr = 0; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 管理メモリ + nptr = reallocate(entry, size, MARK_ALLOCATED, file, line, func, true); + break; + case MARK_DELETED: // 削除済みメモリ + nptr = malloc(size, file, line, func); + break; + case MARK_ALLOCATED_NEW: // new で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new : can't realloc"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new[] : can't realloc"); } + break; + default: // 管理対象外メモリ + nptr = reallocate(ptr, size, MARK_ALLOCATED, file, line, func, false); + } + + return nptr; + } + + + /** + * 指定されたメモリを開放します. + * + * @param ptr 開放するメモリへのポインタ + */ + void free(void* ptr) + { + MemoryInfo* entry; + if (ptr == 0) + { // null ポインタの場合なにもしない + return; + } + + // メモリ管理領域を取得 + entry = (MemoryInfo*) ptr; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 確保されたメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + + } + + +} // namespace MemoryManager +} // namespace scpp + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/modules/libscpp/bkup/scpp_assert.hpp b/modules/libscpp/bkup/scpp_assert.hpp new file mode 100644 index 0000000..094836e --- /dev/null +++ b/modules/libscpp/bkup/scpp_assert.hpp @@ -0,0 +1,29 @@ +/** + * @file scpp_assert.hpp + * @bried Assert モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include + +namespace scpp +{ + + +class AssertError : public std::exception +{ + public: + AssertError() noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string% msg, +}; + + +} + + +#endif // SCPP_ASSERT_HPP diff --git a/modules/libscpp/bkup/scpp_exception.cpp b/modules/libscpp/bkup/scpp_exception.cpp new file mode 100644 index 0000000..5ed0c1c --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.cpp @@ -0,0 +1,13 @@ +/** + * @file scpp_exception.cpp + * @bried Exception モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + + +namespace scpp +{ +} + diff --git a/modules/libscpp/bkup/scpp_exception.hpp b/modules/libscpp/bkup/scpp_exception.hpp new file mode 100644 index 0000000..b37132f --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.hpp @@ -0,0 +1,65 @@ +/** + * @file scpp_exception.hpp + * @bried Exception モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + +/** + * 例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ +class Throwable: public std::exception +{ + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(const std::string& msg) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; +}; + + +/** + * 回復可能な例外クラス。 + */ +class Exception : public Throwable +{ + public: + Exception() noexcept; + Exception(const Throwable& t) noexcept; + Exception(const std::string& msg) noexcept; + virtual ~Exception() noexcept; +}; + + +/** + * 回復困難な例外クラス。 + */ +class Error : public Throwable +{ + public: + Error() noexcept; + Error(const Throwable& t) noexcept; + Error(const std::string& msg) noexcept; + virtual ~Error() noexcept; +}; + + +} + + +#endif // SCPP_EXCEPTION_HPP diff --git a/modules/libscpp/bkup/scpp_memory.cpp b/modules/libscpp/bkup/scpp_memory.cpp new file mode 100644 index 0000000..7213a9d --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.cpp @@ -0,0 +1,693 @@ +/** + * @file scpp_memory.cpp + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include +#include +#include +#include + + +// 本来の malloc, free を利用するため、ENABLED_MEMORY_MANAGE を無効にする +#ifdef ENABLED_MEMORY_MANAGE +#undef ENABLED_MEMORY_MANAGE +#endif +#include + + + +using namespace scpp; +namespace +{ + int const PADDING = sizeof(int) * 2; + int const MARK_ALLOCATED = 0x12340000; + int const MARK_ALLOCATED_NEW = 0x12341111; + int const MARK_ALLOCATED_NEW_ARRAY = 0x12342222; + int const MARK_DELETED = 0xFEDCBA00; + + bool infoIsInitialized = false; + std::mutex memMtx; //< 管理メモリ操作用 Mutex + MemoryInfo infoHead; //< 管理メモリ先頭 + MemoryInfo infoTail; //< 管理メモリ末尾 + MemoryInfo infoError; //< エラー発生時用 + MemoryListener* listener = 0; //< 通知リスナ + + // プロトタイプ宣言 + void init(); + void add(MemoryInfo* entry); + void remove(MemoryInfo* entry); + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func); + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng); + + /** + * new ハンドラを取得します。 + * + * @return new ハンドラ + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + /** + * メモリ管理初期化. + */ + void init() + { + if (!infoIsInitialized) + { + infoIsInitialized = true; + infoHead.fileName = infoTail.fileName = 0; + infoHead.lineNumber = infoTail.lineNumber = 0; + infoHead.functionName = infoTail.functionName = 0; + infoHead.size = infoTail.size = 0; + infoHead._prev = infoHead._next = &infoTail; + infoTail._prev = infoTail._next = &infoHead; + infoHead._mark = infoTail._mark = MARK_DELETED; + + // エラー処理用 + infoError.fileName = 0; + infoError.lineNumber = 0; + infoError.functionName = 0; + infoError.size = 0; + infoError._prev = 0; + infoError._next = 0; + infoError._mark = MARK_DELETED; + } + } + + + /** + * メモリエントリを追加します. + * + * @param entry 追加するエントリ + */ + void add(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + init(); + entry->_next = &infoTail; + entry->_prev = infoTail._prev; + infoTail._prev->_next = entry; + infoTail._prev = entry; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyAlloc(*entry); + } + } + + + /** + * メモリエントリを削除します. + * + * @param entry 削除するエントリ + */ + void remove(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyFree(*entry); + } + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func) + { + MemoryInfo* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast (::malloc(n + sizeof(MemoryInfo) + PADDING)); + if (entry != 0) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { + return 0; + } + } + + void* ptr = (entry + 1); + + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = ptr; + + // エントリに追加 + add(entry); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng) + { + if (isMng) + { // 管理メモリの場合, いったん削除 + remove(static_cast(ptr)); + } + + MemoryInfo* entry = static_cast (::realloc(ptr, n + sizeof(MemoryInfo) + PADDING)); + if (entry == 0) + { + // メモリ確保失敗 -> 元の領域は開放されないので再管理する + add(static_cast(ptr)); + errno = ENOMEM; + if (listener) + { // エラーハンドラが登録されている + infoError.size = n; + infoError.fileName = file; + infoError.lineNumber = line; + infoError.functionName = func; + listener->notifyError(infoError, "can't realloc"); + } + return 0; + } + + if (!isMng) + { // 管理対象外メモリの場合 + // |<---- 新たな確保領域 ---->| + // +----------+---------------+ + // |元々の領域|追加分+管理領域| + // +----------+---------------+ + // ↓ + // +--------+----------+------+ + // |管理領域|元々の領域|追加分| + // +--------+----------+------+ + memmove((entry + 1), entry, n); + } + + // 管理領域に情報を書き込む + void* nptr = (entry + 1); + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = nptr; + + // エントリに追加 + add(entry); + return nptr; + } + +} // namespace 無名 + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 以下, new / delete のオーバライド +// + + +void* operator new(std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new[](std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + +void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + + +void operator delete(void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } +} + +void operator delete(void* p, std::size_t) noexcept +{ + operator delete(p); +} + +void operator delete(void* p, const std::nothrow_t&) noexcept +{ + operator delete(p); +} + +void operator delete[](void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + +} + +void operator delete[](void* p, std::size_t) noexcept +{ + operator delete[](p); +} + +void operator delete[](void* p, const std::nothrow_t&) noexcept +{ + operator delete[](p); +} + + +namespace scpp +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// デフォルトのメモリ確保/開放時に実行されるリスナ +// + +DefaultMemoryListener::DefaultMemoryListener() +{ + // NOP +} +DefaultMemoryListener::~DefaultMemoryListener() +{ + // NOP +} + +/** + * メモリが確保された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyAlloc(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリが開放された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyFree(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリの確保/開放でエラーが発生した際に実行されるリスナ. + * エラー内容をエラー出力します. + * + * @param info メモリ情報 + * @param msg メッセージ + */ +void DefaultMemoryListener::notifyError(const MemoryInfo& info, const std::string& msg) +{ + std::cerr << "MemoryError: " << msg << std::endl; + std::cerr << "\tat " << info.fileName << ":" << info.lineNumber << ":" << info.functionName + << " (size = " << info.size << ")" << std::endl; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理 +// + +/** + * メモリ管理. + * メモリの確保, 開放を行います. + * リスナを登録することで, メモリ確保, 開放, エラー発生時の通知を + * 受信することができます. + * + * 以下のようにメモリを管理しています. + * @code + * + * |<----管理メモリ------------->| + * +--------+--------------------+ + * |管理領域|ユーザ使用メモリ領域| + * +--------+--------------------+ + * ↑ユーザにはこの位置を返す + * + * c++ なので std::list 等を使っても良いが, + * list のメモリ確保でエラーがでると本末転倒なので, + * メモリ確保時に管理領域をまとめて確保&管理する. + * @endcode + * + */ +namespace MemoryManager +{ + + thread_local const char* fileName = ""; // 名前一時保存用 + thread_local int lineNumber = 0; // 行番号一時保存用 + thread_local const char* functionName = ""; // 関数名一時保存用 + + /** + * メモリの確保,開放,エラー発生の通知を受信するリスナを登録します. + * + * @param l リスナ + */ + void setListener(MemoryListener* l) + { + listener = l; + } + + + /** + * 管理している全メモリエントリを引数に指定されたハンドラを実行します. + * デフォルトで用意しているハンドラ printMemoryInfo を使用できます. + * + * @param handler ハンドラ + */ + void entries(void (*handler)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + handler(*info); + info = info->_next; + } + } + + + /** + * 指定されたメソッドが true を返す管理メモリをクリア(削除)します. + * 本メソッド実行時, 管理しているメモリの情報を引数に + * 指定された関数が実行されます. + * + * [注意事項] + * 本メソッドでメモリはクリアしますが, デストラクタは呼び出されないので注意 + * + * 使用例) + * @code + * bool isCleanup(const scpp::MemoryInfo& info) + * { // 管理しているメモリ全てクリアする + * return true; + * } + * scpp::MemoryManager::cleanup(&isCleanup); + * @endcode + * + * @param isCleanup クリアするか否かを返す関数ポインタ + */ + void cleanup(bool (*isCleanup)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + bool ret = isCleanup(*info); + if (ret) + { // クリア対象 + MemoryInfo* tmpInfo; + tmpInfo = info; + info = info->_next; + remove(tmpInfo); + tmpInfo->size = 0; + tmpInfo->_mark = MARK_DELETED; + free(tmpInfo); + } + else + { + info = info->_next; + } + } + } + + + /** + * 指定されたメモリの情報を出力します. + * + * @param info メモリの情報 + */ + void printMemoryInfo(const MemoryInfo& info) + { + std::cout << "[MemoryInfo] " + << info.fileName << ":" + << info.lineNumber << ":" + << info.functionName << " (size = " + << info.size << ")" + << std::endl; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル名 + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, int line, const char* func) + { + void* ptr = allocate(size, MARK_ALLOCATED, file, line, func); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param nmemb 確保するメモリの要素数 + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func) + { + std::size_t n = nmemb * size; + void* ptr = allocate(n, MARK_ALLOCATED, file, line, func); + if (ptr) + { // callc なのでゼロクリアする + memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * ポインタが示すメモリブロックのサイズを変更します. + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func) + { + if (ptr == 0) + { // ptr が null の場合, malloc と等価 + ptr = malloc(size, file, line, func); + return ptr; + } + + if (size == 0) + { // size が 0 の場合, free と等価 + free(ptr); + return 0; + } + + // メモリ管理領域を取得 + MemoryInfo* entry = static_cast (ptr); + entry--; + void* nptr = 0; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 管理メモリ + nptr = reallocate(entry, size, MARK_ALLOCATED, file, line, func, true); + break; + case MARK_DELETED: // 削除済みメモリ + nptr = malloc(size, file, line, func); + break; + case MARK_ALLOCATED_NEW: // new で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new : can't realloc"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new[] : can't realloc"); } + break; + default: // 管理対象外メモリ + nptr = reallocate(ptr, size, MARK_ALLOCATED, file, line, func, false); + } + + return nptr; + } + + + /** + * 指定されたメモリを開放します. + * + * @param ptr 開放するメモリへのポインタ + */ + void free(void* ptr) + { + MemoryInfo* entry; + if (ptr == 0) + { // null ポインタの場合なにもしない + return; + } + + // メモリ管理領域を取得 + entry = (MemoryInfo*) ptr; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 確保されたメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + + } + + +} // namespace MemoryManager +} // namespace scpp + diff --git a/modules/libscpp/bkup/scpp_memory.hpp b/modules/libscpp/bkup/scpp_memory.hpp new file mode 100644 index 0000000..675ab75 --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.hpp @@ -0,0 +1,129 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * メモリの確保/解放/エラー発生時に呼び出されるリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHandler メソッドにて登録することで、 + * メモリの確保/解放/エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager で管理しているメモリに対してのみ有効です。 + * (MemoryManager::malloc, MemoryManager::calloc, MemoryManager::realloc) + * + * new, malloc, calloc などを対象とする場合、 + * ENABLED_MEMORY_MANAGE を定義してください。 + */ + class MemoryListener + { + public: + virtual void notifyAlloc(const MemoryInfo& info) = 0; + virtual void notifyFree(const MemoryInfo& info) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + virtual ~MemoryListener() = 0; + }; + + + /** + * メモリ確保/解放/エラー発生時のデフォルト通知インタフェースです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener&) = delete; + void operator=(const DefaultMemoryListener&) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info); + virtual void notifyFree(const MemoryInfo& info); + virtual void notifyError(const MemoryInfo& info, const std::string& msg); + }; + + + /** + * メモリ管理。 + * メモリの確保、解放を行います。 + * ハンドラを登録することで、メモリの確保/解放/エラー時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* fileName; + extern thread_local int lineNumber; + extern thread_local const char* functionName; + + void setListener(MemoryListener* handler); + void entries(void (*handler)(const MemoryInfo& info)); + void cleanup(bool (*isCleanup)(const MemoryInfo& info)); + void printMemoryInfo(const MemoryInfo& info); + void* malloc( std::size_t size, const char* file, int line, const char* func); + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func); + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func); + void free(void* ptr); + } + +} + + +#if (ENABLED_MEMORY_MANAGE) +#if IS_SUPPORTED_CPP20 +#define SCPP_NODISCARD [[nodiscard]] +#else +#define SCPP_NODISCARD +#endif + +SCPP_NODISCARD void* operator new(std::size_t size); +SCPP_NODISCARD void* operator new[](std::size_t size); + +SCPP_NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +SCPP_NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; + +// void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; + +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; + +// 実質メモリ管理しないので除外 +// SCPP_NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; + +#if IS_SUPPORTED_CPP17 +// 以下、未サポート +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// +#endif + +#define new \ + ((scpp::MemoryManager::fileName = __FILE__, \ + scpp::MemoryManager::lineNumber = __LINE__, \ + scpp::MemoryManager::functionName = __func__, \ + 0) && 0) ? 0 : new + +#define malloc(size) scpp::MemoryManager::malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) scpp::MemoryManager::calloc(nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) scpp::MemoryManager::realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) scpp::MemoryManager::free(ptr) + +#endif // (ENABLED_MEMORY_MANAGE) + +#endif // SCPP_MEMORY_HPP diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/modules/libscpp/bkup/scpp_assert.hpp b/modules/libscpp/bkup/scpp_assert.hpp new file mode 100644 index 0000000..094836e --- /dev/null +++ b/modules/libscpp/bkup/scpp_assert.hpp @@ -0,0 +1,29 @@ +/** + * @file scpp_assert.hpp + * @bried Assert モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include + +namespace scpp +{ + + +class AssertError : public std::exception +{ + public: + AssertError() noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string% msg, +}; + + +} + + +#endif // SCPP_ASSERT_HPP diff --git a/modules/libscpp/bkup/scpp_exception.cpp b/modules/libscpp/bkup/scpp_exception.cpp new file mode 100644 index 0000000..5ed0c1c --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.cpp @@ -0,0 +1,13 @@ +/** + * @file scpp_exception.cpp + * @bried Exception モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + + +namespace scpp +{ +} + diff --git a/modules/libscpp/bkup/scpp_exception.hpp b/modules/libscpp/bkup/scpp_exception.hpp new file mode 100644 index 0000000..b37132f --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.hpp @@ -0,0 +1,65 @@ +/** + * @file scpp_exception.hpp + * @bried Exception モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + +/** + * 例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ +class Throwable: public std::exception +{ + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(const std::string& msg) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; +}; + + +/** + * 回復可能な例外クラス。 + */ +class Exception : public Throwable +{ + public: + Exception() noexcept; + Exception(const Throwable& t) noexcept; + Exception(const std::string& msg) noexcept; + virtual ~Exception() noexcept; +}; + + +/** + * 回復困難な例外クラス。 + */ +class Error : public Throwable +{ + public: + Error() noexcept; + Error(const Throwable& t) noexcept; + Error(const std::string& msg) noexcept; + virtual ~Error() noexcept; +}; + + +} + + +#endif // SCPP_EXCEPTION_HPP diff --git a/modules/libscpp/bkup/scpp_memory.cpp b/modules/libscpp/bkup/scpp_memory.cpp new file mode 100644 index 0000000..7213a9d --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.cpp @@ -0,0 +1,693 @@ +/** + * @file scpp_memory.cpp + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include +#include +#include +#include + + +// 本来の malloc, free を利用するため、ENABLED_MEMORY_MANAGE を無効にする +#ifdef ENABLED_MEMORY_MANAGE +#undef ENABLED_MEMORY_MANAGE +#endif +#include + + + +using namespace scpp; +namespace +{ + int const PADDING = sizeof(int) * 2; + int const MARK_ALLOCATED = 0x12340000; + int const MARK_ALLOCATED_NEW = 0x12341111; + int const MARK_ALLOCATED_NEW_ARRAY = 0x12342222; + int const MARK_DELETED = 0xFEDCBA00; + + bool infoIsInitialized = false; + std::mutex memMtx; //< 管理メモリ操作用 Mutex + MemoryInfo infoHead; //< 管理メモリ先頭 + MemoryInfo infoTail; //< 管理メモリ末尾 + MemoryInfo infoError; //< エラー発生時用 + MemoryListener* listener = 0; //< 通知リスナ + + // プロトタイプ宣言 + void init(); + void add(MemoryInfo* entry); + void remove(MemoryInfo* entry); + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func); + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng); + + /** + * new ハンドラを取得します。 + * + * @return new ハンドラ + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + /** + * メモリ管理初期化. + */ + void init() + { + if (!infoIsInitialized) + { + infoIsInitialized = true; + infoHead.fileName = infoTail.fileName = 0; + infoHead.lineNumber = infoTail.lineNumber = 0; + infoHead.functionName = infoTail.functionName = 0; + infoHead.size = infoTail.size = 0; + infoHead._prev = infoHead._next = &infoTail; + infoTail._prev = infoTail._next = &infoHead; + infoHead._mark = infoTail._mark = MARK_DELETED; + + // エラー処理用 + infoError.fileName = 0; + infoError.lineNumber = 0; + infoError.functionName = 0; + infoError.size = 0; + infoError._prev = 0; + infoError._next = 0; + infoError._mark = MARK_DELETED; + } + } + + + /** + * メモリエントリを追加します. + * + * @param entry 追加するエントリ + */ + void add(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + init(); + entry->_next = &infoTail; + entry->_prev = infoTail._prev; + infoTail._prev->_next = entry; + infoTail._prev = entry; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyAlloc(*entry); + } + } + + + /** + * メモリエントリを削除します. + * + * @param entry 削除するエントリ + */ + void remove(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyFree(*entry); + } + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func) + { + MemoryInfo* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast (::malloc(n + sizeof(MemoryInfo) + PADDING)); + if (entry != 0) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { + return 0; + } + } + + void* ptr = (entry + 1); + + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = ptr; + + // エントリに追加 + add(entry); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng) + { + if (isMng) + { // 管理メモリの場合, いったん削除 + remove(static_cast(ptr)); + } + + MemoryInfo* entry = static_cast (::realloc(ptr, n + sizeof(MemoryInfo) + PADDING)); + if (entry == 0) + { + // メモリ確保失敗 -> 元の領域は開放されないので再管理する + add(static_cast(ptr)); + errno = ENOMEM; + if (listener) + { // エラーハンドラが登録されている + infoError.size = n; + infoError.fileName = file; + infoError.lineNumber = line; + infoError.functionName = func; + listener->notifyError(infoError, "can't realloc"); + } + return 0; + } + + if (!isMng) + { // 管理対象外メモリの場合 + // |<---- 新たな確保領域 ---->| + // +----------+---------------+ + // |元々の領域|追加分+管理領域| + // +----------+---------------+ + // ↓ + // +--------+----------+------+ + // |管理領域|元々の領域|追加分| + // +--------+----------+------+ + memmove((entry + 1), entry, n); + } + + // 管理領域に情報を書き込む + void* nptr = (entry + 1); + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = nptr; + + // エントリに追加 + add(entry); + return nptr; + } + +} // namespace 無名 + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 以下, new / delete のオーバライド +// + + +void* operator new(std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new[](std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + +void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + + +void operator delete(void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } +} + +void operator delete(void* p, std::size_t) noexcept +{ + operator delete(p); +} + +void operator delete(void* p, const std::nothrow_t&) noexcept +{ + operator delete(p); +} + +void operator delete[](void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + +} + +void operator delete[](void* p, std::size_t) noexcept +{ + operator delete[](p); +} + +void operator delete[](void* p, const std::nothrow_t&) noexcept +{ + operator delete[](p); +} + + +namespace scpp +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// デフォルトのメモリ確保/開放時に実行されるリスナ +// + +DefaultMemoryListener::DefaultMemoryListener() +{ + // NOP +} +DefaultMemoryListener::~DefaultMemoryListener() +{ + // NOP +} + +/** + * メモリが確保された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyAlloc(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリが開放された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyFree(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリの確保/開放でエラーが発生した際に実行されるリスナ. + * エラー内容をエラー出力します. + * + * @param info メモリ情報 + * @param msg メッセージ + */ +void DefaultMemoryListener::notifyError(const MemoryInfo& info, const std::string& msg) +{ + std::cerr << "MemoryError: " << msg << std::endl; + std::cerr << "\tat " << info.fileName << ":" << info.lineNumber << ":" << info.functionName + << " (size = " << info.size << ")" << std::endl; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理 +// + +/** + * メモリ管理. + * メモリの確保, 開放を行います. + * リスナを登録することで, メモリ確保, 開放, エラー発生時の通知を + * 受信することができます. + * + * 以下のようにメモリを管理しています. + * @code + * + * |<----管理メモリ------------->| + * +--------+--------------------+ + * |管理領域|ユーザ使用メモリ領域| + * +--------+--------------------+ + * ↑ユーザにはこの位置を返す + * + * c++ なので std::list 等を使っても良いが, + * list のメモリ確保でエラーがでると本末転倒なので, + * メモリ確保時に管理領域をまとめて確保&管理する. + * @endcode + * + */ +namespace MemoryManager +{ + + thread_local const char* fileName = ""; // 名前一時保存用 + thread_local int lineNumber = 0; // 行番号一時保存用 + thread_local const char* functionName = ""; // 関数名一時保存用 + + /** + * メモリの確保,開放,エラー発生の通知を受信するリスナを登録します. + * + * @param l リスナ + */ + void setListener(MemoryListener* l) + { + listener = l; + } + + + /** + * 管理している全メモリエントリを引数に指定されたハンドラを実行します. + * デフォルトで用意しているハンドラ printMemoryInfo を使用できます. + * + * @param handler ハンドラ + */ + void entries(void (*handler)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + handler(*info); + info = info->_next; + } + } + + + /** + * 指定されたメソッドが true を返す管理メモリをクリア(削除)します. + * 本メソッド実行時, 管理しているメモリの情報を引数に + * 指定された関数が実行されます. + * + * [注意事項] + * 本メソッドでメモリはクリアしますが, デストラクタは呼び出されないので注意 + * + * 使用例) + * @code + * bool isCleanup(const scpp::MemoryInfo& info) + * { // 管理しているメモリ全てクリアする + * return true; + * } + * scpp::MemoryManager::cleanup(&isCleanup); + * @endcode + * + * @param isCleanup クリアするか否かを返す関数ポインタ + */ + void cleanup(bool (*isCleanup)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + bool ret = isCleanup(*info); + if (ret) + { // クリア対象 + MemoryInfo* tmpInfo; + tmpInfo = info; + info = info->_next; + remove(tmpInfo); + tmpInfo->size = 0; + tmpInfo->_mark = MARK_DELETED; + free(tmpInfo); + } + else + { + info = info->_next; + } + } + } + + + /** + * 指定されたメモリの情報を出力します. + * + * @param info メモリの情報 + */ + void printMemoryInfo(const MemoryInfo& info) + { + std::cout << "[MemoryInfo] " + << info.fileName << ":" + << info.lineNumber << ":" + << info.functionName << " (size = " + << info.size << ")" + << std::endl; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル名 + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, int line, const char* func) + { + void* ptr = allocate(size, MARK_ALLOCATED, file, line, func); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param nmemb 確保するメモリの要素数 + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func) + { + std::size_t n = nmemb * size; + void* ptr = allocate(n, MARK_ALLOCATED, file, line, func); + if (ptr) + { // callc なのでゼロクリアする + memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * ポインタが示すメモリブロックのサイズを変更します. + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func) + { + if (ptr == 0) + { // ptr が null の場合, malloc と等価 + ptr = malloc(size, file, line, func); + return ptr; + } + + if (size == 0) + { // size が 0 の場合, free と等価 + free(ptr); + return 0; + } + + // メモリ管理領域を取得 + MemoryInfo* entry = static_cast (ptr); + entry--; + void* nptr = 0; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 管理メモリ + nptr = reallocate(entry, size, MARK_ALLOCATED, file, line, func, true); + break; + case MARK_DELETED: // 削除済みメモリ + nptr = malloc(size, file, line, func); + break; + case MARK_ALLOCATED_NEW: // new で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new : can't realloc"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new[] : can't realloc"); } + break; + default: // 管理対象外メモリ + nptr = reallocate(ptr, size, MARK_ALLOCATED, file, line, func, false); + } + + return nptr; + } + + + /** + * 指定されたメモリを開放します. + * + * @param ptr 開放するメモリへのポインタ + */ + void free(void* ptr) + { + MemoryInfo* entry; + if (ptr == 0) + { // null ポインタの場合なにもしない + return; + } + + // メモリ管理領域を取得 + entry = (MemoryInfo*) ptr; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 確保されたメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + + } + + +} // namespace MemoryManager +} // namespace scpp + diff --git a/modules/libscpp/bkup/scpp_memory.hpp b/modules/libscpp/bkup/scpp_memory.hpp new file mode 100644 index 0000000..675ab75 --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.hpp @@ -0,0 +1,129 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * メモリの確保/解放/エラー発生時に呼び出されるリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHandler メソッドにて登録することで、 + * メモリの確保/解放/エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager で管理しているメモリに対してのみ有効です。 + * (MemoryManager::malloc, MemoryManager::calloc, MemoryManager::realloc) + * + * new, malloc, calloc などを対象とする場合、 + * ENABLED_MEMORY_MANAGE を定義してください。 + */ + class MemoryListener + { + public: + virtual void notifyAlloc(const MemoryInfo& info) = 0; + virtual void notifyFree(const MemoryInfo& info) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + virtual ~MemoryListener() = 0; + }; + + + /** + * メモリ確保/解放/エラー発生時のデフォルト通知インタフェースです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener&) = delete; + void operator=(const DefaultMemoryListener&) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info); + virtual void notifyFree(const MemoryInfo& info); + virtual void notifyError(const MemoryInfo& info, const std::string& msg); + }; + + + /** + * メモリ管理。 + * メモリの確保、解放を行います。 + * ハンドラを登録することで、メモリの確保/解放/エラー時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* fileName; + extern thread_local int lineNumber; + extern thread_local const char* functionName; + + void setListener(MemoryListener* handler); + void entries(void (*handler)(const MemoryInfo& info)); + void cleanup(bool (*isCleanup)(const MemoryInfo& info)); + void printMemoryInfo(const MemoryInfo& info); + void* malloc( std::size_t size, const char* file, int line, const char* func); + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func); + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func); + void free(void* ptr); + } + +} + + +#if (ENABLED_MEMORY_MANAGE) +#if IS_SUPPORTED_CPP20 +#define SCPP_NODISCARD [[nodiscard]] +#else +#define SCPP_NODISCARD +#endif + +SCPP_NODISCARD void* operator new(std::size_t size); +SCPP_NODISCARD void* operator new[](std::size_t size); + +SCPP_NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +SCPP_NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; + +// void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; + +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; + +// 実質メモリ管理しないので除外 +// SCPP_NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; + +#if IS_SUPPORTED_CPP17 +// 以下、未サポート +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// +#endif + +#define new \ + ((scpp::MemoryManager::fileName = __FILE__, \ + scpp::MemoryManager::lineNumber = __LINE__, \ + scpp::MemoryManager::functionName = __func__, \ + 0) && 0) ? 0 : new + +#define malloc(size) scpp::MemoryManager::malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) scpp::MemoryManager::calloc(nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) scpp::MemoryManager::realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) scpp::MemoryManager::free(ptr) + +#endif // (ENABLED_MEMORY_MANAGE) + +#endif // SCPP_MEMORY_HPP diff --git a/modules/libscpp/bkup/scpp_unittest.hpp b/modules/libscpp/bkup/scpp_unittest.hpp new file mode 100644 index 0000000..9b2b154 --- /dev/null +++ b/modules/libscpp/bkup/scpp_unittest.hpp @@ -0,0 +1,11 @@ +/** + * @file scpp_unitteset.hpp + * @bried 単体テストモジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_UNITTEST_HPP +#define SCPP_UNITTEST_HPP + + +#endif // SCPP_UNITTEST_HPP diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/modules/libscpp/bkup/scpp_assert.hpp b/modules/libscpp/bkup/scpp_assert.hpp new file mode 100644 index 0000000..094836e --- /dev/null +++ b/modules/libscpp/bkup/scpp_assert.hpp @@ -0,0 +1,29 @@ +/** + * @file scpp_assert.hpp + * @bried Assert モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include + +namespace scpp +{ + + +class AssertError : public std::exception +{ + public: + AssertError() noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string% msg, +}; + + +} + + +#endif // SCPP_ASSERT_HPP diff --git a/modules/libscpp/bkup/scpp_exception.cpp b/modules/libscpp/bkup/scpp_exception.cpp new file mode 100644 index 0000000..5ed0c1c --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.cpp @@ -0,0 +1,13 @@ +/** + * @file scpp_exception.cpp + * @bried Exception モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + + +namespace scpp +{ +} + diff --git a/modules/libscpp/bkup/scpp_exception.hpp b/modules/libscpp/bkup/scpp_exception.hpp new file mode 100644 index 0000000..b37132f --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.hpp @@ -0,0 +1,65 @@ +/** + * @file scpp_exception.hpp + * @bried Exception モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + +/** + * 例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ +class Throwable: public std::exception +{ + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(const std::string& msg) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; +}; + + +/** + * 回復可能な例外クラス。 + */ +class Exception : public Throwable +{ + public: + Exception() noexcept; + Exception(const Throwable& t) noexcept; + Exception(const std::string& msg) noexcept; + virtual ~Exception() noexcept; +}; + + +/** + * 回復困難な例外クラス。 + */ +class Error : public Throwable +{ + public: + Error() noexcept; + Error(const Throwable& t) noexcept; + Error(const std::string& msg) noexcept; + virtual ~Error() noexcept; +}; + + +} + + +#endif // SCPP_EXCEPTION_HPP diff --git a/modules/libscpp/bkup/scpp_memory.cpp b/modules/libscpp/bkup/scpp_memory.cpp new file mode 100644 index 0000000..7213a9d --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.cpp @@ -0,0 +1,693 @@ +/** + * @file scpp_memory.cpp + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include +#include +#include +#include + + +// 本来の malloc, free を利用するため、ENABLED_MEMORY_MANAGE を無効にする +#ifdef ENABLED_MEMORY_MANAGE +#undef ENABLED_MEMORY_MANAGE +#endif +#include + + + +using namespace scpp; +namespace +{ + int const PADDING = sizeof(int) * 2; + int const MARK_ALLOCATED = 0x12340000; + int const MARK_ALLOCATED_NEW = 0x12341111; + int const MARK_ALLOCATED_NEW_ARRAY = 0x12342222; + int const MARK_DELETED = 0xFEDCBA00; + + bool infoIsInitialized = false; + std::mutex memMtx; //< 管理メモリ操作用 Mutex + MemoryInfo infoHead; //< 管理メモリ先頭 + MemoryInfo infoTail; //< 管理メモリ末尾 + MemoryInfo infoError; //< エラー発生時用 + MemoryListener* listener = 0; //< 通知リスナ + + // プロトタイプ宣言 + void init(); + void add(MemoryInfo* entry); + void remove(MemoryInfo* entry); + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func); + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng); + + /** + * new ハンドラを取得します。 + * + * @return new ハンドラ + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + /** + * メモリ管理初期化. + */ + void init() + { + if (!infoIsInitialized) + { + infoIsInitialized = true; + infoHead.fileName = infoTail.fileName = 0; + infoHead.lineNumber = infoTail.lineNumber = 0; + infoHead.functionName = infoTail.functionName = 0; + infoHead.size = infoTail.size = 0; + infoHead._prev = infoHead._next = &infoTail; + infoTail._prev = infoTail._next = &infoHead; + infoHead._mark = infoTail._mark = MARK_DELETED; + + // エラー処理用 + infoError.fileName = 0; + infoError.lineNumber = 0; + infoError.functionName = 0; + infoError.size = 0; + infoError._prev = 0; + infoError._next = 0; + infoError._mark = MARK_DELETED; + } + } + + + /** + * メモリエントリを追加します. + * + * @param entry 追加するエントリ + */ + void add(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + init(); + entry->_next = &infoTail; + entry->_prev = infoTail._prev; + infoTail._prev->_next = entry; + infoTail._prev = entry; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyAlloc(*entry); + } + } + + + /** + * メモリエントリを削除します. + * + * @param entry 削除するエントリ + */ + void remove(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyFree(*entry); + } + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func) + { + MemoryInfo* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast (::malloc(n + sizeof(MemoryInfo) + PADDING)); + if (entry != 0) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { + return 0; + } + } + + void* ptr = (entry + 1); + + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = ptr; + + // エントリに追加 + add(entry); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng) + { + if (isMng) + { // 管理メモリの場合, いったん削除 + remove(static_cast(ptr)); + } + + MemoryInfo* entry = static_cast (::realloc(ptr, n + sizeof(MemoryInfo) + PADDING)); + if (entry == 0) + { + // メモリ確保失敗 -> 元の領域は開放されないので再管理する + add(static_cast(ptr)); + errno = ENOMEM; + if (listener) + { // エラーハンドラが登録されている + infoError.size = n; + infoError.fileName = file; + infoError.lineNumber = line; + infoError.functionName = func; + listener->notifyError(infoError, "can't realloc"); + } + return 0; + } + + if (!isMng) + { // 管理対象外メモリの場合 + // |<---- 新たな確保領域 ---->| + // +----------+---------------+ + // |元々の領域|追加分+管理領域| + // +----------+---------------+ + // ↓ + // +--------+----------+------+ + // |管理領域|元々の領域|追加分| + // +--------+----------+------+ + memmove((entry + 1), entry, n); + } + + // 管理領域に情報を書き込む + void* nptr = (entry + 1); + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = nptr; + + // エントリに追加 + add(entry); + return nptr; + } + +} // namespace 無名 + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 以下, new / delete のオーバライド +// + + +void* operator new(std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new[](std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + +void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + + +void operator delete(void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } +} + +void operator delete(void* p, std::size_t) noexcept +{ + operator delete(p); +} + +void operator delete(void* p, const std::nothrow_t&) noexcept +{ + operator delete(p); +} + +void operator delete[](void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + +} + +void operator delete[](void* p, std::size_t) noexcept +{ + operator delete[](p); +} + +void operator delete[](void* p, const std::nothrow_t&) noexcept +{ + operator delete[](p); +} + + +namespace scpp +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// デフォルトのメモリ確保/開放時に実行されるリスナ +// + +DefaultMemoryListener::DefaultMemoryListener() +{ + // NOP +} +DefaultMemoryListener::~DefaultMemoryListener() +{ + // NOP +} + +/** + * メモリが確保された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyAlloc(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリが開放された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyFree(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリの確保/開放でエラーが発生した際に実行されるリスナ. + * エラー内容をエラー出力します. + * + * @param info メモリ情報 + * @param msg メッセージ + */ +void DefaultMemoryListener::notifyError(const MemoryInfo& info, const std::string& msg) +{ + std::cerr << "MemoryError: " << msg << std::endl; + std::cerr << "\tat " << info.fileName << ":" << info.lineNumber << ":" << info.functionName + << " (size = " << info.size << ")" << std::endl; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理 +// + +/** + * メモリ管理. + * メモリの確保, 開放を行います. + * リスナを登録することで, メモリ確保, 開放, エラー発生時の通知を + * 受信することができます. + * + * 以下のようにメモリを管理しています. + * @code + * + * |<----管理メモリ------------->| + * +--------+--------------------+ + * |管理領域|ユーザ使用メモリ領域| + * +--------+--------------------+ + * ↑ユーザにはこの位置を返す + * + * c++ なので std::list 等を使っても良いが, + * list のメモリ確保でエラーがでると本末転倒なので, + * メモリ確保時に管理領域をまとめて確保&管理する. + * @endcode + * + */ +namespace MemoryManager +{ + + thread_local const char* fileName = ""; // 名前一時保存用 + thread_local int lineNumber = 0; // 行番号一時保存用 + thread_local const char* functionName = ""; // 関数名一時保存用 + + /** + * メモリの確保,開放,エラー発生の通知を受信するリスナを登録します. + * + * @param l リスナ + */ + void setListener(MemoryListener* l) + { + listener = l; + } + + + /** + * 管理している全メモリエントリを引数に指定されたハンドラを実行します. + * デフォルトで用意しているハンドラ printMemoryInfo を使用できます. + * + * @param handler ハンドラ + */ + void entries(void (*handler)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + handler(*info); + info = info->_next; + } + } + + + /** + * 指定されたメソッドが true を返す管理メモリをクリア(削除)します. + * 本メソッド実行時, 管理しているメモリの情報を引数に + * 指定された関数が実行されます. + * + * [注意事項] + * 本メソッドでメモリはクリアしますが, デストラクタは呼び出されないので注意 + * + * 使用例) + * @code + * bool isCleanup(const scpp::MemoryInfo& info) + * { // 管理しているメモリ全てクリアする + * return true; + * } + * scpp::MemoryManager::cleanup(&isCleanup); + * @endcode + * + * @param isCleanup クリアするか否かを返す関数ポインタ + */ + void cleanup(bool (*isCleanup)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + bool ret = isCleanup(*info); + if (ret) + { // クリア対象 + MemoryInfo* tmpInfo; + tmpInfo = info; + info = info->_next; + remove(tmpInfo); + tmpInfo->size = 0; + tmpInfo->_mark = MARK_DELETED; + free(tmpInfo); + } + else + { + info = info->_next; + } + } + } + + + /** + * 指定されたメモリの情報を出力します. + * + * @param info メモリの情報 + */ + void printMemoryInfo(const MemoryInfo& info) + { + std::cout << "[MemoryInfo] " + << info.fileName << ":" + << info.lineNumber << ":" + << info.functionName << " (size = " + << info.size << ")" + << std::endl; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル名 + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, int line, const char* func) + { + void* ptr = allocate(size, MARK_ALLOCATED, file, line, func); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param nmemb 確保するメモリの要素数 + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func) + { + std::size_t n = nmemb * size; + void* ptr = allocate(n, MARK_ALLOCATED, file, line, func); + if (ptr) + { // callc なのでゼロクリアする + memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * ポインタが示すメモリブロックのサイズを変更します. + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func) + { + if (ptr == 0) + { // ptr が null の場合, malloc と等価 + ptr = malloc(size, file, line, func); + return ptr; + } + + if (size == 0) + { // size が 0 の場合, free と等価 + free(ptr); + return 0; + } + + // メモリ管理領域を取得 + MemoryInfo* entry = static_cast (ptr); + entry--; + void* nptr = 0; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 管理メモリ + nptr = reallocate(entry, size, MARK_ALLOCATED, file, line, func, true); + break; + case MARK_DELETED: // 削除済みメモリ + nptr = malloc(size, file, line, func); + break; + case MARK_ALLOCATED_NEW: // new で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new : can't realloc"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new[] : can't realloc"); } + break; + default: // 管理対象外メモリ + nptr = reallocate(ptr, size, MARK_ALLOCATED, file, line, func, false); + } + + return nptr; + } + + + /** + * 指定されたメモリを開放します. + * + * @param ptr 開放するメモリへのポインタ + */ + void free(void* ptr) + { + MemoryInfo* entry; + if (ptr == 0) + { // null ポインタの場合なにもしない + return; + } + + // メモリ管理領域を取得 + entry = (MemoryInfo*) ptr; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 確保されたメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + + } + + +} // namespace MemoryManager +} // namespace scpp + diff --git a/modules/libscpp/bkup/scpp_memory.hpp b/modules/libscpp/bkup/scpp_memory.hpp new file mode 100644 index 0000000..675ab75 --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.hpp @@ -0,0 +1,129 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * メモリの確保/解放/エラー発生時に呼び出されるリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHandler メソッドにて登録することで、 + * メモリの確保/解放/エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager で管理しているメモリに対してのみ有効です。 + * (MemoryManager::malloc, MemoryManager::calloc, MemoryManager::realloc) + * + * new, malloc, calloc などを対象とする場合、 + * ENABLED_MEMORY_MANAGE を定義してください。 + */ + class MemoryListener + { + public: + virtual void notifyAlloc(const MemoryInfo& info) = 0; + virtual void notifyFree(const MemoryInfo& info) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + virtual ~MemoryListener() = 0; + }; + + + /** + * メモリ確保/解放/エラー発生時のデフォルト通知インタフェースです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener&) = delete; + void operator=(const DefaultMemoryListener&) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info); + virtual void notifyFree(const MemoryInfo& info); + virtual void notifyError(const MemoryInfo& info, const std::string& msg); + }; + + + /** + * メモリ管理。 + * メモリの確保、解放を行います。 + * ハンドラを登録することで、メモリの確保/解放/エラー時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* fileName; + extern thread_local int lineNumber; + extern thread_local const char* functionName; + + void setListener(MemoryListener* handler); + void entries(void (*handler)(const MemoryInfo& info)); + void cleanup(bool (*isCleanup)(const MemoryInfo& info)); + void printMemoryInfo(const MemoryInfo& info); + void* malloc( std::size_t size, const char* file, int line, const char* func); + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func); + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func); + void free(void* ptr); + } + +} + + +#if (ENABLED_MEMORY_MANAGE) +#if IS_SUPPORTED_CPP20 +#define SCPP_NODISCARD [[nodiscard]] +#else +#define SCPP_NODISCARD +#endif + +SCPP_NODISCARD void* operator new(std::size_t size); +SCPP_NODISCARD void* operator new[](std::size_t size); + +SCPP_NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +SCPP_NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; + +// void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; + +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; + +// 実質メモリ管理しないので除外 +// SCPP_NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; + +#if IS_SUPPORTED_CPP17 +// 以下、未サポート +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// +#endif + +#define new \ + ((scpp::MemoryManager::fileName = __FILE__, \ + scpp::MemoryManager::lineNumber = __LINE__, \ + scpp::MemoryManager::functionName = __func__, \ + 0) && 0) ? 0 : new + +#define malloc(size) scpp::MemoryManager::malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) scpp::MemoryManager::calloc(nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) scpp::MemoryManager::realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) scpp::MemoryManager::free(ptr) + +#endif // (ENABLED_MEMORY_MANAGE) + +#endif // SCPP_MEMORY_HPP diff --git a/modules/libscpp/bkup/scpp_unittest.hpp b/modules/libscpp/bkup/scpp_unittest.hpp new file mode 100644 index 0000000..9b2b154 --- /dev/null +++ b/modules/libscpp/bkup/scpp_unittest.hpp @@ -0,0 +1,11 @@ +/** + * @file scpp_unitteset.hpp + * @bried 単体テストモジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_UNITTEST_HPP +#define SCPP_UNITTEST_HPP + + +#endif // SCPP_UNITTEST_HPP diff --git a/modules/libscpp/include/scpp.hpp b/modules/libscpp/include/scpp.hpp new file mode 100644 index 0000000..00aaa98 --- /dev/null +++ b/modules/libscpp/include/scpp.hpp @@ -0,0 +1,15 @@ +/** + * @file scpp.hpp + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include +#include +#include + +#endif // SCPP_H + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/modules/libscpp/bkup/scpp_assert.hpp b/modules/libscpp/bkup/scpp_assert.hpp new file mode 100644 index 0000000..094836e --- /dev/null +++ b/modules/libscpp/bkup/scpp_assert.hpp @@ -0,0 +1,29 @@ +/** + * @file scpp_assert.hpp + * @bried Assert モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include + +namespace scpp +{ + + +class AssertError : public std::exception +{ + public: + AssertError() noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string% msg, +}; + + +} + + +#endif // SCPP_ASSERT_HPP diff --git a/modules/libscpp/bkup/scpp_exception.cpp b/modules/libscpp/bkup/scpp_exception.cpp new file mode 100644 index 0000000..5ed0c1c --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.cpp @@ -0,0 +1,13 @@ +/** + * @file scpp_exception.cpp + * @bried Exception モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + + +namespace scpp +{ +} + diff --git a/modules/libscpp/bkup/scpp_exception.hpp b/modules/libscpp/bkup/scpp_exception.hpp new file mode 100644 index 0000000..b37132f --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.hpp @@ -0,0 +1,65 @@ +/** + * @file scpp_exception.hpp + * @bried Exception モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + +/** + * 例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ +class Throwable: public std::exception +{ + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(const std::string& msg) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; +}; + + +/** + * 回復可能な例外クラス。 + */ +class Exception : public Throwable +{ + public: + Exception() noexcept; + Exception(const Throwable& t) noexcept; + Exception(const std::string& msg) noexcept; + virtual ~Exception() noexcept; +}; + + +/** + * 回復困難な例外クラス。 + */ +class Error : public Throwable +{ + public: + Error() noexcept; + Error(const Throwable& t) noexcept; + Error(const std::string& msg) noexcept; + virtual ~Error() noexcept; +}; + + +} + + +#endif // SCPP_EXCEPTION_HPP diff --git a/modules/libscpp/bkup/scpp_memory.cpp b/modules/libscpp/bkup/scpp_memory.cpp new file mode 100644 index 0000000..7213a9d --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.cpp @@ -0,0 +1,693 @@ +/** + * @file scpp_memory.cpp + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include +#include +#include +#include + + +// 本来の malloc, free を利用するため、ENABLED_MEMORY_MANAGE を無効にする +#ifdef ENABLED_MEMORY_MANAGE +#undef ENABLED_MEMORY_MANAGE +#endif +#include + + + +using namespace scpp; +namespace +{ + int const PADDING = sizeof(int) * 2; + int const MARK_ALLOCATED = 0x12340000; + int const MARK_ALLOCATED_NEW = 0x12341111; + int const MARK_ALLOCATED_NEW_ARRAY = 0x12342222; + int const MARK_DELETED = 0xFEDCBA00; + + bool infoIsInitialized = false; + std::mutex memMtx; //< 管理メモリ操作用 Mutex + MemoryInfo infoHead; //< 管理メモリ先頭 + MemoryInfo infoTail; //< 管理メモリ末尾 + MemoryInfo infoError; //< エラー発生時用 + MemoryListener* listener = 0; //< 通知リスナ + + // プロトタイプ宣言 + void init(); + void add(MemoryInfo* entry); + void remove(MemoryInfo* entry); + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func); + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng); + + /** + * new ハンドラを取得します。 + * + * @return new ハンドラ + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + /** + * メモリ管理初期化. + */ + void init() + { + if (!infoIsInitialized) + { + infoIsInitialized = true; + infoHead.fileName = infoTail.fileName = 0; + infoHead.lineNumber = infoTail.lineNumber = 0; + infoHead.functionName = infoTail.functionName = 0; + infoHead.size = infoTail.size = 0; + infoHead._prev = infoHead._next = &infoTail; + infoTail._prev = infoTail._next = &infoHead; + infoHead._mark = infoTail._mark = MARK_DELETED; + + // エラー処理用 + infoError.fileName = 0; + infoError.lineNumber = 0; + infoError.functionName = 0; + infoError.size = 0; + infoError._prev = 0; + infoError._next = 0; + infoError._mark = MARK_DELETED; + } + } + + + /** + * メモリエントリを追加します. + * + * @param entry 追加するエントリ + */ + void add(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + init(); + entry->_next = &infoTail; + entry->_prev = infoTail._prev; + infoTail._prev->_next = entry; + infoTail._prev = entry; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyAlloc(*entry); + } + } + + + /** + * メモリエントリを削除します. + * + * @param entry 削除するエントリ + */ + void remove(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyFree(*entry); + } + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func) + { + MemoryInfo* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast (::malloc(n + sizeof(MemoryInfo) + PADDING)); + if (entry != 0) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { + return 0; + } + } + + void* ptr = (entry + 1); + + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = ptr; + + // エントリに追加 + add(entry); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng) + { + if (isMng) + { // 管理メモリの場合, いったん削除 + remove(static_cast(ptr)); + } + + MemoryInfo* entry = static_cast (::realloc(ptr, n + sizeof(MemoryInfo) + PADDING)); + if (entry == 0) + { + // メモリ確保失敗 -> 元の領域は開放されないので再管理する + add(static_cast(ptr)); + errno = ENOMEM; + if (listener) + { // エラーハンドラが登録されている + infoError.size = n; + infoError.fileName = file; + infoError.lineNumber = line; + infoError.functionName = func; + listener->notifyError(infoError, "can't realloc"); + } + return 0; + } + + if (!isMng) + { // 管理対象外メモリの場合 + // |<---- 新たな確保領域 ---->| + // +----------+---------------+ + // |元々の領域|追加分+管理領域| + // +----------+---------------+ + // ↓ + // +--------+----------+------+ + // |管理領域|元々の領域|追加分| + // +--------+----------+------+ + memmove((entry + 1), entry, n); + } + + // 管理領域に情報を書き込む + void* nptr = (entry + 1); + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = nptr; + + // エントリに追加 + add(entry); + return nptr; + } + +} // namespace 無名 + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 以下, new / delete のオーバライド +// + + +void* operator new(std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new[](std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + +void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + + +void operator delete(void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } +} + +void operator delete(void* p, std::size_t) noexcept +{ + operator delete(p); +} + +void operator delete(void* p, const std::nothrow_t&) noexcept +{ + operator delete(p); +} + +void operator delete[](void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + +} + +void operator delete[](void* p, std::size_t) noexcept +{ + operator delete[](p); +} + +void operator delete[](void* p, const std::nothrow_t&) noexcept +{ + operator delete[](p); +} + + +namespace scpp +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// デフォルトのメモリ確保/開放時に実行されるリスナ +// + +DefaultMemoryListener::DefaultMemoryListener() +{ + // NOP +} +DefaultMemoryListener::~DefaultMemoryListener() +{ + // NOP +} + +/** + * メモリが確保された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyAlloc(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリが開放された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyFree(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリの確保/開放でエラーが発生した際に実行されるリスナ. + * エラー内容をエラー出力します. + * + * @param info メモリ情報 + * @param msg メッセージ + */ +void DefaultMemoryListener::notifyError(const MemoryInfo& info, const std::string& msg) +{ + std::cerr << "MemoryError: " << msg << std::endl; + std::cerr << "\tat " << info.fileName << ":" << info.lineNumber << ":" << info.functionName + << " (size = " << info.size << ")" << std::endl; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理 +// + +/** + * メモリ管理. + * メモリの確保, 開放を行います. + * リスナを登録することで, メモリ確保, 開放, エラー発生時の通知を + * 受信することができます. + * + * 以下のようにメモリを管理しています. + * @code + * + * |<----管理メモリ------------->| + * +--------+--------------------+ + * |管理領域|ユーザ使用メモリ領域| + * +--------+--------------------+ + * ↑ユーザにはこの位置を返す + * + * c++ なので std::list 等を使っても良いが, + * list のメモリ確保でエラーがでると本末転倒なので, + * メモリ確保時に管理領域をまとめて確保&管理する. + * @endcode + * + */ +namespace MemoryManager +{ + + thread_local const char* fileName = ""; // 名前一時保存用 + thread_local int lineNumber = 0; // 行番号一時保存用 + thread_local const char* functionName = ""; // 関数名一時保存用 + + /** + * メモリの確保,開放,エラー発生の通知を受信するリスナを登録します. + * + * @param l リスナ + */ + void setListener(MemoryListener* l) + { + listener = l; + } + + + /** + * 管理している全メモリエントリを引数に指定されたハンドラを実行します. + * デフォルトで用意しているハンドラ printMemoryInfo を使用できます. + * + * @param handler ハンドラ + */ + void entries(void (*handler)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + handler(*info); + info = info->_next; + } + } + + + /** + * 指定されたメソッドが true を返す管理メモリをクリア(削除)します. + * 本メソッド実行時, 管理しているメモリの情報を引数に + * 指定された関数が実行されます. + * + * [注意事項] + * 本メソッドでメモリはクリアしますが, デストラクタは呼び出されないので注意 + * + * 使用例) + * @code + * bool isCleanup(const scpp::MemoryInfo& info) + * { // 管理しているメモリ全てクリアする + * return true; + * } + * scpp::MemoryManager::cleanup(&isCleanup); + * @endcode + * + * @param isCleanup クリアするか否かを返す関数ポインタ + */ + void cleanup(bool (*isCleanup)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + bool ret = isCleanup(*info); + if (ret) + { // クリア対象 + MemoryInfo* tmpInfo; + tmpInfo = info; + info = info->_next; + remove(tmpInfo); + tmpInfo->size = 0; + tmpInfo->_mark = MARK_DELETED; + free(tmpInfo); + } + else + { + info = info->_next; + } + } + } + + + /** + * 指定されたメモリの情報を出力します. + * + * @param info メモリの情報 + */ + void printMemoryInfo(const MemoryInfo& info) + { + std::cout << "[MemoryInfo] " + << info.fileName << ":" + << info.lineNumber << ":" + << info.functionName << " (size = " + << info.size << ")" + << std::endl; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル名 + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, int line, const char* func) + { + void* ptr = allocate(size, MARK_ALLOCATED, file, line, func); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param nmemb 確保するメモリの要素数 + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func) + { + std::size_t n = nmemb * size; + void* ptr = allocate(n, MARK_ALLOCATED, file, line, func); + if (ptr) + { // callc なのでゼロクリアする + memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * ポインタが示すメモリブロックのサイズを変更します. + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func) + { + if (ptr == 0) + { // ptr が null の場合, malloc と等価 + ptr = malloc(size, file, line, func); + return ptr; + } + + if (size == 0) + { // size が 0 の場合, free と等価 + free(ptr); + return 0; + } + + // メモリ管理領域を取得 + MemoryInfo* entry = static_cast (ptr); + entry--; + void* nptr = 0; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 管理メモリ + nptr = reallocate(entry, size, MARK_ALLOCATED, file, line, func, true); + break; + case MARK_DELETED: // 削除済みメモリ + nptr = malloc(size, file, line, func); + break; + case MARK_ALLOCATED_NEW: // new で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new : can't realloc"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new[] : can't realloc"); } + break; + default: // 管理対象外メモリ + nptr = reallocate(ptr, size, MARK_ALLOCATED, file, line, func, false); + } + + return nptr; + } + + + /** + * 指定されたメモリを開放します. + * + * @param ptr 開放するメモリへのポインタ + */ + void free(void* ptr) + { + MemoryInfo* entry; + if (ptr == 0) + { // null ポインタの場合なにもしない + return; + } + + // メモリ管理領域を取得 + entry = (MemoryInfo*) ptr; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 確保されたメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + + } + + +} // namespace MemoryManager +} // namespace scpp + diff --git a/modules/libscpp/bkup/scpp_memory.hpp b/modules/libscpp/bkup/scpp_memory.hpp new file mode 100644 index 0000000..675ab75 --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.hpp @@ -0,0 +1,129 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * メモリの確保/解放/エラー発生時に呼び出されるリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHandler メソッドにて登録することで、 + * メモリの確保/解放/エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager で管理しているメモリに対してのみ有効です。 + * (MemoryManager::malloc, MemoryManager::calloc, MemoryManager::realloc) + * + * new, malloc, calloc などを対象とする場合、 + * ENABLED_MEMORY_MANAGE を定義してください。 + */ + class MemoryListener + { + public: + virtual void notifyAlloc(const MemoryInfo& info) = 0; + virtual void notifyFree(const MemoryInfo& info) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + virtual ~MemoryListener() = 0; + }; + + + /** + * メモリ確保/解放/エラー発生時のデフォルト通知インタフェースです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener&) = delete; + void operator=(const DefaultMemoryListener&) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info); + virtual void notifyFree(const MemoryInfo& info); + virtual void notifyError(const MemoryInfo& info, const std::string& msg); + }; + + + /** + * メモリ管理。 + * メモリの確保、解放を行います。 + * ハンドラを登録することで、メモリの確保/解放/エラー時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* fileName; + extern thread_local int lineNumber; + extern thread_local const char* functionName; + + void setListener(MemoryListener* handler); + void entries(void (*handler)(const MemoryInfo& info)); + void cleanup(bool (*isCleanup)(const MemoryInfo& info)); + void printMemoryInfo(const MemoryInfo& info); + void* malloc( std::size_t size, const char* file, int line, const char* func); + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func); + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func); + void free(void* ptr); + } + +} + + +#if (ENABLED_MEMORY_MANAGE) +#if IS_SUPPORTED_CPP20 +#define SCPP_NODISCARD [[nodiscard]] +#else +#define SCPP_NODISCARD +#endif + +SCPP_NODISCARD void* operator new(std::size_t size); +SCPP_NODISCARD void* operator new[](std::size_t size); + +SCPP_NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +SCPP_NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; + +// void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; + +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; + +// 実質メモリ管理しないので除外 +// SCPP_NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; + +#if IS_SUPPORTED_CPP17 +// 以下、未サポート +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// +#endif + +#define new \ + ((scpp::MemoryManager::fileName = __FILE__, \ + scpp::MemoryManager::lineNumber = __LINE__, \ + scpp::MemoryManager::functionName = __func__, \ + 0) && 0) ? 0 : new + +#define malloc(size) scpp::MemoryManager::malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) scpp::MemoryManager::calloc(nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) scpp::MemoryManager::realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) scpp::MemoryManager::free(ptr) + +#endif // (ENABLED_MEMORY_MANAGE) + +#endif // SCPP_MEMORY_HPP diff --git a/modules/libscpp/bkup/scpp_unittest.hpp b/modules/libscpp/bkup/scpp_unittest.hpp new file mode 100644 index 0000000..9b2b154 --- /dev/null +++ b/modules/libscpp/bkup/scpp_unittest.hpp @@ -0,0 +1,11 @@ +/** + * @file scpp_unitteset.hpp + * @bried 単体テストモジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_UNITTEST_HPP +#define SCPP_UNITTEST_HPP + + +#endif // SCPP_UNITTEST_HPP diff --git a/modules/libscpp/include/scpp.hpp b/modules/libscpp/include/scpp.hpp new file mode 100644 index 0000000..00aaa98 --- /dev/null +++ b/modules/libscpp/include/scpp.hpp @@ -0,0 +1,15 @@ +/** + * @file scpp.hpp + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include +#include +#include + +#endif // SCPP_H + diff --git a/modules/libscpp/include/scpp_assert.hpp b/modules/libscpp/include/scpp_assert.hpp new file mode 100644 index 0000000..76aeb30 --- /dev/null +++ b/modules/libscpp/include/scpp_assert.hpp @@ -0,0 +1,24 @@ +/** + * @file scpp_assert.hpp + * @bried アサーションモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * アサーション関数が失敗するとき、エラーメッセージを出力します。 + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include +#include + +namespace scpp +{ + +/** + * アサーションに失敗した際に throw される Erro です。 + */ + + +#endif // SCPP_ASSERT_HPP + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/modules/libscpp/bkup/scpp_assert.hpp b/modules/libscpp/bkup/scpp_assert.hpp new file mode 100644 index 0000000..094836e --- /dev/null +++ b/modules/libscpp/bkup/scpp_assert.hpp @@ -0,0 +1,29 @@ +/** + * @file scpp_assert.hpp + * @bried Assert モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include + +namespace scpp +{ + + +class AssertError : public std::exception +{ + public: + AssertError() noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string% msg, +}; + + +} + + +#endif // SCPP_ASSERT_HPP diff --git a/modules/libscpp/bkup/scpp_exception.cpp b/modules/libscpp/bkup/scpp_exception.cpp new file mode 100644 index 0000000..5ed0c1c --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.cpp @@ -0,0 +1,13 @@ +/** + * @file scpp_exception.cpp + * @bried Exception モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + + +namespace scpp +{ +} + diff --git a/modules/libscpp/bkup/scpp_exception.hpp b/modules/libscpp/bkup/scpp_exception.hpp new file mode 100644 index 0000000..b37132f --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.hpp @@ -0,0 +1,65 @@ +/** + * @file scpp_exception.hpp + * @bried Exception モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + +/** + * 例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ +class Throwable: public std::exception +{ + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(const std::string& msg) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; +}; + + +/** + * 回復可能な例外クラス。 + */ +class Exception : public Throwable +{ + public: + Exception() noexcept; + Exception(const Throwable& t) noexcept; + Exception(const std::string& msg) noexcept; + virtual ~Exception() noexcept; +}; + + +/** + * 回復困難な例外クラス。 + */ +class Error : public Throwable +{ + public: + Error() noexcept; + Error(const Throwable& t) noexcept; + Error(const std::string& msg) noexcept; + virtual ~Error() noexcept; +}; + + +} + + +#endif // SCPP_EXCEPTION_HPP diff --git a/modules/libscpp/bkup/scpp_memory.cpp b/modules/libscpp/bkup/scpp_memory.cpp new file mode 100644 index 0000000..7213a9d --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.cpp @@ -0,0 +1,693 @@ +/** + * @file scpp_memory.cpp + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include +#include +#include +#include + + +// 本来の malloc, free を利用するため、ENABLED_MEMORY_MANAGE を無効にする +#ifdef ENABLED_MEMORY_MANAGE +#undef ENABLED_MEMORY_MANAGE +#endif +#include + + + +using namespace scpp; +namespace +{ + int const PADDING = sizeof(int) * 2; + int const MARK_ALLOCATED = 0x12340000; + int const MARK_ALLOCATED_NEW = 0x12341111; + int const MARK_ALLOCATED_NEW_ARRAY = 0x12342222; + int const MARK_DELETED = 0xFEDCBA00; + + bool infoIsInitialized = false; + std::mutex memMtx; //< 管理メモリ操作用 Mutex + MemoryInfo infoHead; //< 管理メモリ先頭 + MemoryInfo infoTail; //< 管理メモリ末尾 + MemoryInfo infoError; //< エラー発生時用 + MemoryListener* listener = 0; //< 通知リスナ + + // プロトタイプ宣言 + void init(); + void add(MemoryInfo* entry); + void remove(MemoryInfo* entry); + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func); + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng); + + /** + * new ハンドラを取得します。 + * + * @return new ハンドラ + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + /** + * メモリ管理初期化. + */ + void init() + { + if (!infoIsInitialized) + { + infoIsInitialized = true; + infoHead.fileName = infoTail.fileName = 0; + infoHead.lineNumber = infoTail.lineNumber = 0; + infoHead.functionName = infoTail.functionName = 0; + infoHead.size = infoTail.size = 0; + infoHead._prev = infoHead._next = &infoTail; + infoTail._prev = infoTail._next = &infoHead; + infoHead._mark = infoTail._mark = MARK_DELETED; + + // エラー処理用 + infoError.fileName = 0; + infoError.lineNumber = 0; + infoError.functionName = 0; + infoError.size = 0; + infoError._prev = 0; + infoError._next = 0; + infoError._mark = MARK_DELETED; + } + } + + + /** + * メモリエントリを追加します. + * + * @param entry 追加するエントリ + */ + void add(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + init(); + entry->_next = &infoTail; + entry->_prev = infoTail._prev; + infoTail._prev->_next = entry; + infoTail._prev = entry; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyAlloc(*entry); + } + } + + + /** + * メモリエントリを削除します. + * + * @param entry 削除するエントリ + */ + void remove(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyFree(*entry); + } + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func) + { + MemoryInfo* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast (::malloc(n + sizeof(MemoryInfo) + PADDING)); + if (entry != 0) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { + return 0; + } + } + + void* ptr = (entry + 1); + + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = ptr; + + // エントリに追加 + add(entry); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng) + { + if (isMng) + { // 管理メモリの場合, いったん削除 + remove(static_cast(ptr)); + } + + MemoryInfo* entry = static_cast (::realloc(ptr, n + sizeof(MemoryInfo) + PADDING)); + if (entry == 0) + { + // メモリ確保失敗 -> 元の領域は開放されないので再管理する + add(static_cast(ptr)); + errno = ENOMEM; + if (listener) + { // エラーハンドラが登録されている + infoError.size = n; + infoError.fileName = file; + infoError.lineNumber = line; + infoError.functionName = func; + listener->notifyError(infoError, "can't realloc"); + } + return 0; + } + + if (!isMng) + { // 管理対象外メモリの場合 + // |<---- 新たな確保領域 ---->| + // +----------+---------------+ + // |元々の領域|追加分+管理領域| + // +----------+---------------+ + // ↓ + // +--------+----------+------+ + // |管理領域|元々の領域|追加分| + // +--------+----------+------+ + memmove((entry + 1), entry, n); + } + + // 管理領域に情報を書き込む + void* nptr = (entry + 1); + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = nptr; + + // エントリに追加 + add(entry); + return nptr; + } + +} // namespace 無名 + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 以下, new / delete のオーバライド +// + + +void* operator new(std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new[](std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + +void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + + +void operator delete(void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } +} + +void operator delete(void* p, std::size_t) noexcept +{ + operator delete(p); +} + +void operator delete(void* p, const std::nothrow_t&) noexcept +{ + operator delete(p); +} + +void operator delete[](void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + +} + +void operator delete[](void* p, std::size_t) noexcept +{ + operator delete[](p); +} + +void operator delete[](void* p, const std::nothrow_t&) noexcept +{ + operator delete[](p); +} + + +namespace scpp +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// デフォルトのメモリ確保/開放時に実行されるリスナ +// + +DefaultMemoryListener::DefaultMemoryListener() +{ + // NOP +} +DefaultMemoryListener::~DefaultMemoryListener() +{ + // NOP +} + +/** + * メモリが確保された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyAlloc(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリが開放された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyFree(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリの確保/開放でエラーが発生した際に実行されるリスナ. + * エラー内容をエラー出力します. + * + * @param info メモリ情報 + * @param msg メッセージ + */ +void DefaultMemoryListener::notifyError(const MemoryInfo& info, const std::string& msg) +{ + std::cerr << "MemoryError: " << msg << std::endl; + std::cerr << "\tat " << info.fileName << ":" << info.lineNumber << ":" << info.functionName + << " (size = " << info.size << ")" << std::endl; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理 +// + +/** + * メモリ管理. + * メモリの確保, 開放を行います. + * リスナを登録することで, メモリ確保, 開放, エラー発生時の通知を + * 受信することができます. + * + * 以下のようにメモリを管理しています. + * @code + * + * |<----管理メモリ------------->| + * +--------+--------------------+ + * |管理領域|ユーザ使用メモリ領域| + * +--------+--------------------+ + * ↑ユーザにはこの位置を返す + * + * c++ なので std::list 等を使っても良いが, + * list のメモリ確保でエラーがでると本末転倒なので, + * メモリ確保時に管理領域をまとめて確保&管理する. + * @endcode + * + */ +namespace MemoryManager +{ + + thread_local const char* fileName = ""; // 名前一時保存用 + thread_local int lineNumber = 0; // 行番号一時保存用 + thread_local const char* functionName = ""; // 関数名一時保存用 + + /** + * メモリの確保,開放,エラー発生の通知を受信するリスナを登録します. + * + * @param l リスナ + */ + void setListener(MemoryListener* l) + { + listener = l; + } + + + /** + * 管理している全メモリエントリを引数に指定されたハンドラを実行します. + * デフォルトで用意しているハンドラ printMemoryInfo を使用できます. + * + * @param handler ハンドラ + */ + void entries(void (*handler)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + handler(*info); + info = info->_next; + } + } + + + /** + * 指定されたメソッドが true を返す管理メモリをクリア(削除)します. + * 本メソッド実行時, 管理しているメモリの情報を引数に + * 指定された関数が実行されます. + * + * [注意事項] + * 本メソッドでメモリはクリアしますが, デストラクタは呼び出されないので注意 + * + * 使用例) + * @code + * bool isCleanup(const scpp::MemoryInfo& info) + * { // 管理しているメモリ全てクリアする + * return true; + * } + * scpp::MemoryManager::cleanup(&isCleanup); + * @endcode + * + * @param isCleanup クリアするか否かを返す関数ポインタ + */ + void cleanup(bool (*isCleanup)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + bool ret = isCleanup(*info); + if (ret) + { // クリア対象 + MemoryInfo* tmpInfo; + tmpInfo = info; + info = info->_next; + remove(tmpInfo); + tmpInfo->size = 0; + tmpInfo->_mark = MARK_DELETED; + free(tmpInfo); + } + else + { + info = info->_next; + } + } + } + + + /** + * 指定されたメモリの情報を出力します. + * + * @param info メモリの情報 + */ + void printMemoryInfo(const MemoryInfo& info) + { + std::cout << "[MemoryInfo] " + << info.fileName << ":" + << info.lineNumber << ":" + << info.functionName << " (size = " + << info.size << ")" + << std::endl; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル名 + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, int line, const char* func) + { + void* ptr = allocate(size, MARK_ALLOCATED, file, line, func); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param nmemb 確保するメモリの要素数 + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func) + { + std::size_t n = nmemb * size; + void* ptr = allocate(n, MARK_ALLOCATED, file, line, func); + if (ptr) + { // callc なのでゼロクリアする + memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * ポインタが示すメモリブロックのサイズを変更します. + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func) + { + if (ptr == 0) + { // ptr が null の場合, malloc と等価 + ptr = malloc(size, file, line, func); + return ptr; + } + + if (size == 0) + { // size が 0 の場合, free と等価 + free(ptr); + return 0; + } + + // メモリ管理領域を取得 + MemoryInfo* entry = static_cast (ptr); + entry--; + void* nptr = 0; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 管理メモリ + nptr = reallocate(entry, size, MARK_ALLOCATED, file, line, func, true); + break; + case MARK_DELETED: // 削除済みメモリ + nptr = malloc(size, file, line, func); + break; + case MARK_ALLOCATED_NEW: // new で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new : can't realloc"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new[] : can't realloc"); } + break; + default: // 管理対象外メモリ + nptr = reallocate(ptr, size, MARK_ALLOCATED, file, line, func, false); + } + + return nptr; + } + + + /** + * 指定されたメモリを開放します. + * + * @param ptr 開放するメモリへのポインタ + */ + void free(void* ptr) + { + MemoryInfo* entry; + if (ptr == 0) + { // null ポインタの場合なにもしない + return; + } + + // メモリ管理領域を取得 + entry = (MemoryInfo*) ptr; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 確保されたメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + + } + + +} // namespace MemoryManager +} // namespace scpp + diff --git a/modules/libscpp/bkup/scpp_memory.hpp b/modules/libscpp/bkup/scpp_memory.hpp new file mode 100644 index 0000000..675ab75 --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.hpp @@ -0,0 +1,129 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * メモリの確保/解放/エラー発生時に呼び出されるリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHandler メソッドにて登録することで、 + * メモリの確保/解放/エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager で管理しているメモリに対してのみ有効です。 + * (MemoryManager::malloc, MemoryManager::calloc, MemoryManager::realloc) + * + * new, malloc, calloc などを対象とする場合、 + * ENABLED_MEMORY_MANAGE を定義してください。 + */ + class MemoryListener + { + public: + virtual void notifyAlloc(const MemoryInfo& info) = 0; + virtual void notifyFree(const MemoryInfo& info) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + virtual ~MemoryListener() = 0; + }; + + + /** + * メモリ確保/解放/エラー発生時のデフォルト通知インタフェースです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener&) = delete; + void operator=(const DefaultMemoryListener&) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info); + virtual void notifyFree(const MemoryInfo& info); + virtual void notifyError(const MemoryInfo& info, const std::string& msg); + }; + + + /** + * メモリ管理。 + * メモリの確保、解放を行います。 + * ハンドラを登録することで、メモリの確保/解放/エラー時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* fileName; + extern thread_local int lineNumber; + extern thread_local const char* functionName; + + void setListener(MemoryListener* handler); + void entries(void (*handler)(const MemoryInfo& info)); + void cleanup(bool (*isCleanup)(const MemoryInfo& info)); + void printMemoryInfo(const MemoryInfo& info); + void* malloc( std::size_t size, const char* file, int line, const char* func); + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func); + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func); + void free(void* ptr); + } + +} + + +#if (ENABLED_MEMORY_MANAGE) +#if IS_SUPPORTED_CPP20 +#define SCPP_NODISCARD [[nodiscard]] +#else +#define SCPP_NODISCARD +#endif + +SCPP_NODISCARD void* operator new(std::size_t size); +SCPP_NODISCARD void* operator new[](std::size_t size); + +SCPP_NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +SCPP_NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; + +// void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; + +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; + +// 実質メモリ管理しないので除外 +// SCPP_NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; + +#if IS_SUPPORTED_CPP17 +// 以下、未サポート +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// +#endif + +#define new \ + ((scpp::MemoryManager::fileName = __FILE__, \ + scpp::MemoryManager::lineNumber = __LINE__, \ + scpp::MemoryManager::functionName = __func__, \ + 0) && 0) ? 0 : new + +#define malloc(size) scpp::MemoryManager::malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) scpp::MemoryManager::calloc(nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) scpp::MemoryManager::realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) scpp::MemoryManager::free(ptr) + +#endif // (ENABLED_MEMORY_MANAGE) + +#endif // SCPP_MEMORY_HPP diff --git a/modules/libscpp/bkup/scpp_unittest.hpp b/modules/libscpp/bkup/scpp_unittest.hpp new file mode 100644 index 0000000..9b2b154 --- /dev/null +++ b/modules/libscpp/bkup/scpp_unittest.hpp @@ -0,0 +1,11 @@ +/** + * @file scpp_unitteset.hpp + * @bried 単体テストモジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_UNITTEST_HPP +#define SCPP_UNITTEST_HPP + + +#endif // SCPP_UNITTEST_HPP diff --git a/modules/libscpp/include/scpp.hpp b/modules/libscpp/include/scpp.hpp new file mode 100644 index 0000000..00aaa98 --- /dev/null +++ b/modules/libscpp/include/scpp.hpp @@ -0,0 +1,15 @@ +/** + * @file scpp.hpp + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include +#include +#include + +#endif // SCPP_H + diff --git a/modules/libscpp/include/scpp_assert.hpp b/modules/libscpp/include/scpp_assert.hpp new file mode 100644 index 0000000..76aeb30 --- /dev/null +++ b/modules/libscpp/include/scpp_assert.hpp @@ -0,0 +1,24 @@ +/** + * @file scpp_assert.hpp + * @bried アサーションモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * アサーション関数が失敗するとき、エラーメッセージを出力します。 + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include +#include + +namespace scpp +{ + +/** + * アサーションに失敗した際に throw される Erro です。 + */ + + +#endif // SCPP_ASSERT_HPP + diff --git a/modules/libscpp/include/scpp_compiler.hpp b/modules/libscpp/include/scpp_compiler.hpp new file mode 100644 index 0000000..c56a6e2 --- /dev/null +++ b/modules/libscpp/include/scpp_compiler.hpp @@ -0,0 +1,42 @@ +/** + * @file scpp_compiler.hpp + * @bried C++言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C++言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + */ +#ifndef SCPP_COMPILER_H +#define SCPP_COMPILER_H +#ifdef __cplusplus + + +#if (__cplusplus >= 201103L) +/* ----- C++11 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (__cplusplus >= 202002L) +#define IS_SUPPORTED_CPP17 (__cplusplus >= 201703L) +#define IS_SUPPORTED_CPP14 (__cplusplus >= 201402L) +#define IS_SUPPORTED_CPP11 (__cplusplus >= 201103L) +#define IS_SUPPORTED_C17 (0) +#define IS_SUPPORTED_C11 (0) +#define IS_SUPPORTED_C99 (0) + +#else +/* ----- C++11 以前の場合はエラーとする */ +#error "unsupported c++ version, please use c++11 or later" + +#endif /* (__cplusplus >= 201103L) */ + + +#endif /* __cplusplus */ +#endif /* SCPP_COMPILER_H */ diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/modules/libscpp/bkup/scpp_assert.hpp b/modules/libscpp/bkup/scpp_assert.hpp new file mode 100644 index 0000000..094836e --- /dev/null +++ b/modules/libscpp/bkup/scpp_assert.hpp @@ -0,0 +1,29 @@ +/** + * @file scpp_assert.hpp + * @bried Assert モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include + +namespace scpp +{ + + +class AssertError : public std::exception +{ + public: + AssertError() noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string% msg, +}; + + +} + + +#endif // SCPP_ASSERT_HPP diff --git a/modules/libscpp/bkup/scpp_exception.cpp b/modules/libscpp/bkup/scpp_exception.cpp new file mode 100644 index 0000000..5ed0c1c --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.cpp @@ -0,0 +1,13 @@ +/** + * @file scpp_exception.cpp + * @bried Exception モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + + +namespace scpp +{ +} + diff --git a/modules/libscpp/bkup/scpp_exception.hpp b/modules/libscpp/bkup/scpp_exception.hpp new file mode 100644 index 0000000..b37132f --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.hpp @@ -0,0 +1,65 @@ +/** + * @file scpp_exception.hpp + * @bried Exception モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + +/** + * 例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ +class Throwable: public std::exception +{ + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(const std::string& msg) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; +}; + + +/** + * 回復可能な例外クラス。 + */ +class Exception : public Throwable +{ + public: + Exception() noexcept; + Exception(const Throwable& t) noexcept; + Exception(const std::string& msg) noexcept; + virtual ~Exception() noexcept; +}; + + +/** + * 回復困難な例外クラス。 + */ +class Error : public Throwable +{ + public: + Error() noexcept; + Error(const Throwable& t) noexcept; + Error(const std::string& msg) noexcept; + virtual ~Error() noexcept; +}; + + +} + + +#endif // SCPP_EXCEPTION_HPP diff --git a/modules/libscpp/bkup/scpp_memory.cpp b/modules/libscpp/bkup/scpp_memory.cpp new file mode 100644 index 0000000..7213a9d --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.cpp @@ -0,0 +1,693 @@ +/** + * @file scpp_memory.cpp + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include +#include +#include +#include + + +// 本来の malloc, free を利用するため、ENABLED_MEMORY_MANAGE を無効にする +#ifdef ENABLED_MEMORY_MANAGE +#undef ENABLED_MEMORY_MANAGE +#endif +#include + + + +using namespace scpp; +namespace +{ + int const PADDING = sizeof(int) * 2; + int const MARK_ALLOCATED = 0x12340000; + int const MARK_ALLOCATED_NEW = 0x12341111; + int const MARK_ALLOCATED_NEW_ARRAY = 0x12342222; + int const MARK_DELETED = 0xFEDCBA00; + + bool infoIsInitialized = false; + std::mutex memMtx; //< 管理メモリ操作用 Mutex + MemoryInfo infoHead; //< 管理メモリ先頭 + MemoryInfo infoTail; //< 管理メモリ末尾 + MemoryInfo infoError; //< エラー発生時用 + MemoryListener* listener = 0; //< 通知リスナ + + // プロトタイプ宣言 + void init(); + void add(MemoryInfo* entry); + void remove(MemoryInfo* entry); + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func); + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng); + + /** + * new ハンドラを取得します。 + * + * @return new ハンドラ + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + /** + * メモリ管理初期化. + */ + void init() + { + if (!infoIsInitialized) + { + infoIsInitialized = true; + infoHead.fileName = infoTail.fileName = 0; + infoHead.lineNumber = infoTail.lineNumber = 0; + infoHead.functionName = infoTail.functionName = 0; + infoHead.size = infoTail.size = 0; + infoHead._prev = infoHead._next = &infoTail; + infoTail._prev = infoTail._next = &infoHead; + infoHead._mark = infoTail._mark = MARK_DELETED; + + // エラー処理用 + infoError.fileName = 0; + infoError.lineNumber = 0; + infoError.functionName = 0; + infoError.size = 0; + infoError._prev = 0; + infoError._next = 0; + infoError._mark = MARK_DELETED; + } + } + + + /** + * メモリエントリを追加します. + * + * @param entry 追加するエントリ + */ + void add(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + init(); + entry->_next = &infoTail; + entry->_prev = infoTail._prev; + infoTail._prev->_next = entry; + infoTail._prev = entry; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyAlloc(*entry); + } + } + + + /** + * メモリエントリを削除します. + * + * @param entry 削除するエントリ + */ + void remove(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyFree(*entry); + } + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func) + { + MemoryInfo* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast (::malloc(n + sizeof(MemoryInfo) + PADDING)); + if (entry != 0) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { + return 0; + } + } + + void* ptr = (entry + 1); + + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = ptr; + + // エントリに追加 + add(entry); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng) + { + if (isMng) + { // 管理メモリの場合, いったん削除 + remove(static_cast(ptr)); + } + + MemoryInfo* entry = static_cast (::realloc(ptr, n + sizeof(MemoryInfo) + PADDING)); + if (entry == 0) + { + // メモリ確保失敗 -> 元の領域は開放されないので再管理する + add(static_cast(ptr)); + errno = ENOMEM; + if (listener) + { // エラーハンドラが登録されている + infoError.size = n; + infoError.fileName = file; + infoError.lineNumber = line; + infoError.functionName = func; + listener->notifyError(infoError, "can't realloc"); + } + return 0; + } + + if (!isMng) + { // 管理対象外メモリの場合 + // |<---- 新たな確保領域 ---->| + // +----------+---------------+ + // |元々の領域|追加分+管理領域| + // +----------+---------------+ + // ↓ + // +--------+----------+------+ + // |管理領域|元々の領域|追加分| + // +--------+----------+------+ + memmove((entry + 1), entry, n); + } + + // 管理領域に情報を書き込む + void* nptr = (entry + 1); + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = nptr; + + // エントリに追加 + add(entry); + return nptr; + } + +} // namespace 無名 + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 以下, new / delete のオーバライド +// + + +void* operator new(std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new[](std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + +void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + + +void operator delete(void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } +} + +void operator delete(void* p, std::size_t) noexcept +{ + operator delete(p); +} + +void operator delete(void* p, const std::nothrow_t&) noexcept +{ + operator delete(p); +} + +void operator delete[](void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + +} + +void operator delete[](void* p, std::size_t) noexcept +{ + operator delete[](p); +} + +void operator delete[](void* p, const std::nothrow_t&) noexcept +{ + operator delete[](p); +} + + +namespace scpp +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// デフォルトのメモリ確保/開放時に実行されるリスナ +// + +DefaultMemoryListener::DefaultMemoryListener() +{ + // NOP +} +DefaultMemoryListener::~DefaultMemoryListener() +{ + // NOP +} + +/** + * メモリが確保された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyAlloc(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリが開放された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyFree(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリの確保/開放でエラーが発生した際に実行されるリスナ. + * エラー内容をエラー出力します. + * + * @param info メモリ情報 + * @param msg メッセージ + */ +void DefaultMemoryListener::notifyError(const MemoryInfo& info, const std::string& msg) +{ + std::cerr << "MemoryError: " << msg << std::endl; + std::cerr << "\tat " << info.fileName << ":" << info.lineNumber << ":" << info.functionName + << " (size = " << info.size << ")" << std::endl; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理 +// + +/** + * メモリ管理. + * メモリの確保, 開放を行います. + * リスナを登録することで, メモリ確保, 開放, エラー発生時の通知を + * 受信することができます. + * + * 以下のようにメモリを管理しています. + * @code + * + * |<----管理メモリ------------->| + * +--------+--------------------+ + * |管理領域|ユーザ使用メモリ領域| + * +--------+--------------------+ + * ↑ユーザにはこの位置を返す + * + * c++ なので std::list 等を使っても良いが, + * list のメモリ確保でエラーがでると本末転倒なので, + * メモリ確保時に管理領域をまとめて確保&管理する. + * @endcode + * + */ +namespace MemoryManager +{ + + thread_local const char* fileName = ""; // 名前一時保存用 + thread_local int lineNumber = 0; // 行番号一時保存用 + thread_local const char* functionName = ""; // 関数名一時保存用 + + /** + * メモリの確保,開放,エラー発生の通知を受信するリスナを登録します. + * + * @param l リスナ + */ + void setListener(MemoryListener* l) + { + listener = l; + } + + + /** + * 管理している全メモリエントリを引数に指定されたハンドラを実行します. + * デフォルトで用意しているハンドラ printMemoryInfo を使用できます. + * + * @param handler ハンドラ + */ + void entries(void (*handler)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + handler(*info); + info = info->_next; + } + } + + + /** + * 指定されたメソッドが true を返す管理メモリをクリア(削除)します. + * 本メソッド実行時, 管理しているメモリの情報を引数に + * 指定された関数が実行されます. + * + * [注意事項] + * 本メソッドでメモリはクリアしますが, デストラクタは呼び出されないので注意 + * + * 使用例) + * @code + * bool isCleanup(const scpp::MemoryInfo& info) + * { // 管理しているメモリ全てクリアする + * return true; + * } + * scpp::MemoryManager::cleanup(&isCleanup); + * @endcode + * + * @param isCleanup クリアするか否かを返す関数ポインタ + */ + void cleanup(bool (*isCleanup)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + bool ret = isCleanup(*info); + if (ret) + { // クリア対象 + MemoryInfo* tmpInfo; + tmpInfo = info; + info = info->_next; + remove(tmpInfo); + tmpInfo->size = 0; + tmpInfo->_mark = MARK_DELETED; + free(tmpInfo); + } + else + { + info = info->_next; + } + } + } + + + /** + * 指定されたメモリの情報を出力します. + * + * @param info メモリの情報 + */ + void printMemoryInfo(const MemoryInfo& info) + { + std::cout << "[MemoryInfo] " + << info.fileName << ":" + << info.lineNumber << ":" + << info.functionName << " (size = " + << info.size << ")" + << std::endl; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル名 + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, int line, const char* func) + { + void* ptr = allocate(size, MARK_ALLOCATED, file, line, func); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param nmemb 確保するメモリの要素数 + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func) + { + std::size_t n = nmemb * size; + void* ptr = allocate(n, MARK_ALLOCATED, file, line, func); + if (ptr) + { // callc なのでゼロクリアする + memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * ポインタが示すメモリブロックのサイズを変更します. + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func) + { + if (ptr == 0) + { // ptr が null の場合, malloc と等価 + ptr = malloc(size, file, line, func); + return ptr; + } + + if (size == 0) + { // size が 0 の場合, free と等価 + free(ptr); + return 0; + } + + // メモリ管理領域を取得 + MemoryInfo* entry = static_cast (ptr); + entry--; + void* nptr = 0; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 管理メモリ + nptr = reallocate(entry, size, MARK_ALLOCATED, file, line, func, true); + break; + case MARK_DELETED: // 削除済みメモリ + nptr = malloc(size, file, line, func); + break; + case MARK_ALLOCATED_NEW: // new で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new : can't realloc"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new[] : can't realloc"); } + break; + default: // 管理対象外メモリ + nptr = reallocate(ptr, size, MARK_ALLOCATED, file, line, func, false); + } + + return nptr; + } + + + /** + * 指定されたメモリを開放します. + * + * @param ptr 開放するメモリへのポインタ + */ + void free(void* ptr) + { + MemoryInfo* entry; + if (ptr == 0) + { // null ポインタの場合なにもしない + return; + } + + // メモリ管理領域を取得 + entry = (MemoryInfo*) ptr; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 確保されたメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + + } + + +} // namespace MemoryManager +} // namespace scpp + diff --git a/modules/libscpp/bkup/scpp_memory.hpp b/modules/libscpp/bkup/scpp_memory.hpp new file mode 100644 index 0000000..675ab75 --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.hpp @@ -0,0 +1,129 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * メモリの確保/解放/エラー発生時に呼び出されるリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHandler メソッドにて登録することで、 + * メモリの確保/解放/エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager で管理しているメモリに対してのみ有効です。 + * (MemoryManager::malloc, MemoryManager::calloc, MemoryManager::realloc) + * + * new, malloc, calloc などを対象とする場合、 + * ENABLED_MEMORY_MANAGE を定義してください。 + */ + class MemoryListener + { + public: + virtual void notifyAlloc(const MemoryInfo& info) = 0; + virtual void notifyFree(const MemoryInfo& info) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + virtual ~MemoryListener() = 0; + }; + + + /** + * メモリ確保/解放/エラー発生時のデフォルト通知インタフェースです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener&) = delete; + void operator=(const DefaultMemoryListener&) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info); + virtual void notifyFree(const MemoryInfo& info); + virtual void notifyError(const MemoryInfo& info, const std::string& msg); + }; + + + /** + * メモリ管理。 + * メモリの確保、解放を行います。 + * ハンドラを登録することで、メモリの確保/解放/エラー時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* fileName; + extern thread_local int lineNumber; + extern thread_local const char* functionName; + + void setListener(MemoryListener* handler); + void entries(void (*handler)(const MemoryInfo& info)); + void cleanup(bool (*isCleanup)(const MemoryInfo& info)); + void printMemoryInfo(const MemoryInfo& info); + void* malloc( std::size_t size, const char* file, int line, const char* func); + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func); + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func); + void free(void* ptr); + } + +} + + +#if (ENABLED_MEMORY_MANAGE) +#if IS_SUPPORTED_CPP20 +#define SCPP_NODISCARD [[nodiscard]] +#else +#define SCPP_NODISCARD +#endif + +SCPP_NODISCARD void* operator new(std::size_t size); +SCPP_NODISCARD void* operator new[](std::size_t size); + +SCPP_NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +SCPP_NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; + +// void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; + +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; + +// 実質メモリ管理しないので除外 +// SCPP_NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; + +#if IS_SUPPORTED_CPP17 +// 以下、未サポート +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// +#endif + +#define new \ + ((scpp::MemoryManager::fileName = __FILE__, \ + scpp::MemoryManager::lineNumber = __LINE__, \ + scpp::MemoryManager::functionName = __func__, \ + 0) && 0) ? 0 : new + +#define malloc(size) scpp::MemoryManager::malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) scpp::MemoryManager::calloc(nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) scpp::MemoryManager::realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) scpp::MemoryManager::free(ptr) + +#endif // (ENABLED_MEMORY_MANAGE) + +#endif // SCPP_MEMORY_HPP diff --git a/modules/libscpp/bkup/scpp_unittest.hpp b/modules/libscpp/bkup/scpp_unittest.hpp new file mode 100644 index 0000000..9b2b154 --- /dev/null +++ b/modules/libscpp/bkup/scpp_unittest.hpp @@ -0,0 +1,11 @@ +/** + * @file scpp_unitteset.hpp + * @bried 単体テストモジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_UNITTEST_HPP +#define SCPP_UNITTEST_HPP + + +#endif // SCPP_UNITTEST_HPP diff --git a/modules/libscpp/include/scpp.hpp b/modules/libscpp/include/scpp.hpp new file mode 100644 index 0000000..00aaa98 --- /dev/null +++ b/modules/libscpp/include/scpp.hpp @@ -0,0 +1,15 @@ +/** + * @file scpp.hpp + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include +#include +#include + +#endif // SCPP_H + diff --git a/modules/libscpp/include/scpp_assert.hpp b/modules/libscpp/include/scpp_assert.hpp new file mode 100644 index 0000000..76aeb30 --- /dev/null +++ b/modules/libscpp/include/scpp_assert.hpp @@ -0,0 +1,24 @@ +/** + * @file scpp_assert.hpp + * @bried アサーションモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * アサーション関数が失敗するとき、エラーメッセージを出力します。 + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include +#include + +namespace scpp +{ + +/** + * アサーションに失敗した際に throw される Erro です。 + */ + + +#endif // SCPP_ASSERT_HPP + diff --git a/modules/libscpp/include/scpp_compiler.hpp b/modules/libscpp/include/scpp_compiler.hpp new file mode 100644 index 0000000..c56a6e2 --- /dev/null +++ b/modules/libscpp/include/scpp_compiler.hpp @@ -0,0 +1,42 @@ +/** + * @file scpp_compiler.hpp + * @bried C++言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C++言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + */ +#ifndef SCPP_COMPILER_H +#define SCPP_COMPILER_H +#ifdef __cplusplus + + +#if (__cplusplus >= 201103L) +/* ----- C++11 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (__cplusplus >= 202002L) +#define IS_SUPPORTED_CPP17 (__cplusplus >= 201703L) +#define IS_SUPPORTED_CPP14 (__cplusplus >= 201402L) +#define IS_SUPPORTED_CPP11 (__cplusplus >= 201103L) +#define IS_SUPPORTED_C17 (0) +#define IS_SUPPORTED_C11 (0) +#define IS_SUPPORTED_C99 (0) + +#else +/* ----- C++11 以前の場合はエラーとする */ +#error "unsupported c++ version, please use c++11 or later" + +#endif /* (__cplusplus >= 201103L) */ + + +#endif /* __cplusplus */ +#endif /* SCPP_COMPILER_H */ diff --git a/modules/libscpp/include/scpp_exception.hpp b/modules/libscpp/include/scpp_exception.hpp new file mode 100644 index 0000000..70df85f --- /dev/null +++ b/modules/libscpp/include/scpp_exception.hpp @@ -0,0 +1,77 @@ +/** + * @file scpp_exception.hpp + * @bried 例外クラス用ヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * 本ライブラリの例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ + class Throwable : public std::exception + { + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(Throwable&& t) noexcept; + Throwable(const std::string& msg) noexcept; + Throwable& operator=(const Throwable& t) noexcept; + Throwable& operator=(Throwable&& t) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; + }; + + + /** + * 本ライブラリの Exception クラス。 + * 本ライブラリにて発生したエラーのうち、回復可能なエラーは、 + * 本クラスを継承した Exception クラスを throw します。 + */ + class Exception : public Throwable + { + public: + Exception() noexcept; + Exception(const Exception& e) noexcept; + Exception(Exception&& e) noexcept; + Exception(const std::string& msg) noexcept; + Exception& operator=(const Exception& t) noexcept; + Exception& operator=(Exception&& t) noexcept; + virtual ~Exception() noexcept; + }; + + + /** + * 本ライブラリの Error クラス。 + * 本ライブラリにて発生したエラーのうち、回復困難なエラーは、 + * 本クラスを継承した Error クラスを throw します。 + */ + class Error : public Throwable + { + public: + Error() noexcept; + Error(const Error& t) noexcept; + Error(Error&& t) noexcept; + Error(const std::string& msg) noexcept; + Error& operator=(const Error& t) noexcept; + Error& operator=(Error&& t) noexcept; + virtual ~Error() noexcept; + }; + +} // namespace scpp + +#endif // SCPP_EXCEPTION_HPP + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/modules/libscpp/bkup/scpp_assert.hpp b/modules/libscpp/bkup/scpp_assert.hpp new file mode 100644 index 0000000..094836e --- /dev/null +++ b/modules/libscpp/bkup/scpp_assert.hpp @@ -0,0 +1,29 @@ +/** + * @file scpp_assert.hpp + * @bried Assert モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include + +namespace scpp +{ + + +class AssertError : public std::exception +{ + public: + AssertError() noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string% msg, +}; + + +} + + +#endif // SCPP_ASSERT_HPP diff --git a/modules/libscpp/bkup/scpp_exception.cpp b/modules/libscpp/bkup/scpp_exception.cpp new file mode 100644 index 0000000..5ed0c1c --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.cpp @@ -0,0 +1,13 @@ +/** + * @file scpp_exception.cpp + * @bried Exception モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + + +namespace scpp +{ +} + diff --git a/modules/libscpp/bkup/scpp_exception.hpp b/modules/libscpp/bkup/scpp_exception.hpp new file mode 100644 index 0000000..b37132f --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.hpp @@ -0,0 +1,65 @@ +/** + * @file scpp_exception.hpp + * @bried Exception モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + +/** + * 例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ +class Throwable: public std::exception +{ + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(const std::string& msg) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; +}; + + +/** + * 回復可能な例外クラス。 + */ +class Exception : public Throwable +{ + public: + Exception() noexcept; + Exception(const Throwable& t) noexcept; + Exception(const std::string& msg) noexcept; + virtual ~Exception() noexcept; +}; + + +/** + * 回復困難な例外クラス。 + */ +class Error : public Throwable +{ + public: + Error() noexcept; + Error(const Throwable& t) noexcept; + Error(const std::string& msg) noexcept; + virtual ~Error() noexcept; +}; + + +} + + +#endif // SCPP_EXCEPTION_HPP diff --git a/modules/libscpp/bkup/scpp_memory.cpp b/modules/libscpp/bkup/scpp_memory.cpp new file mode 100644 index 0000000..7213a9d --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.cpp @@ -0,0 +1,693 @@ +/** + * @file scpp_memory.cpp + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include +#include +#include +#include + + +// 本来の malloc, free を利用するため、ENABLED_MEMORY_MANAGE を無効にする +#ifdef ENABLED_MEMORY_MANAGE +#undef ENABLED_MEMORY_MANAGE +#endif +#include + + + +using namespace scpp; +namespace +{ + int const PADDING = sizeof(int) * 2; + int const MARK_ALLOCATED = 0x12340000; + int const MARK_ALLOCATED_NEW = 0x12341111; + int const MARK_ALLOCATED_NEW_ARRAY = 0x12342222; + int const MARK_DELETED = 0xFEDCBA00; + + bool infoIsInitialized = false; + std::mutex memMtx; //< 管理メモリ操作用 Mutex + MemoryInfo infoHead; //< 管理メモリ先頭 + MemoryInfo infoTail; //< 管理メモリ末尾 + MemoryInfo infoError; //< エラー発生時用 + MemoryListener* listener = 0; //< 通知リスナ + + // プロトタイプ宣言 + void init(); + void add(MemoryInfo* entry); + void remove(MemoryInfo* entry); + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func); + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng); + + /** + * new ハンドラを取得します。 + * + * @return new ハンドラ + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + /** + * メモリ管理初期化. + */ + void init() + { + if (!infoIsInitialized) + { + infoIsInitialized = true; + infoHead.fileName = infoTail.fileName = 0; + infoHead.lineNumber = infoTail.lineNumber = 0; + infoHead.functionName = infoTail.functionName = 0; + infoHead.size = infoTail.size = 0; + infoHead._prev = infoHead._next = &infoTail; + infoTail._prev = infoTail._next = &infoHead; + infoHead._mark = infoTail._mark = MARK_DELETED; + + // エラー処理用 + infoError.fileName = 0; + infoError.lineNumber = 0; + infoError.functionName = 0; + infoError.size = 0; + infoError._prev = 0; + infoError._next = 0; + infoError._mark = MARK_DELETED; + } + } + + + /** + * メモリエントリを追加します. + * + * @param entry 追加するエントリ + */ + void add(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + init(); + entry->_next = &infoTail; + entry->_prev = infoTail._prev; + infoTail._prev->_next = entry; + infoTail._prev = entry; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyAlloc(*entry); + } + } + + + /** + * メモリエントリを削除します. + * + * @param entry 削除するエントリ + */ + void remove(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyFree(*entry); + } + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func) + { + MemoryInfo* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast (::malloc(n + sizeof(MemoryInfo) + PADDING)); + if (entry != 0) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { + return 0; + } + } + + void* ptr = (entry + 1); + + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = ptr; + + // エントリに追加 + add(entry); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng) + { + if (isMng) + { // 管理メモリの場合, いったん削除 + remove(static_cast(ptr)); + } + + MemoryInfo* entry = static_cast (::realloc(ptr, n + sizeof(MemoryInfo) + PADDING)); + if (entry == 0) + { + // メモリ確保失敗 -> 元の領域は開放されないので再管理する + add(static_cast(ptr)); + errno = ENOMEM; + if (listener) + { // エラーハンドラが登録されている + infoError.size = n; + infoError.fileName = file; + infoError.lineNumber = line; + infoError.functionName = func; + listener->notifyError(infoError, "can't realloc"); + } + return 0; + } + + if (!isMng) + { // 管理対象外メモリの場合 + // |<---- 新たな確保領域 ---->| + // +----------+---------------+ + // |元々の領域|追加分+管理領域| + // +----------+---------------+ + // ↓ + // +--------+----------+------+ + // |管理領域|元々の領域|追加分| + // +--------+----------+------+ + memmove((entry + 1), entry, n); + } + + // 管理領域に情報を書き込む + void* nptr = (entry + 1); + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = nptr; + + // エントリに追加 + add(entry); + return nptr; + } + +} // namespace 無名 + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 以下, new / delete のオーバライド +// + + +void* operator new(std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new[](std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + +void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + + +void operator delete(void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } +} + +void operator delete(void* p, std::size_t) noexcept +{ + operator delete(p); +} + +void operator delete(void* p, const std::nothrow_t&) noexcept +{ + operator delete(p); +} + +void operator delete[](void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + +} + +void operator delete[](void* p, std::size_t) noexcept +{ + operator delete[](p); +} + +void operator delete[](void* p, const std::nothrow_t&) noexcept +{ + operator delete[](p); +} + + +namespace scpp +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// デフォルトのメモリ確保/開放時に実行されるリスナ +// + +DefaultMemoryListener::DefaultMemoryListener() +{ + // NOP +} +DefaultMemoryListener::~DefaultMemoryListener() +{ + // NOP +} + +/** + * メモリが確保された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyAlloc(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリが開放された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyFree(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリの確保/開放でエラーが発生した際に実行されるリスナ. + * エラー内容をエラー出力します. + * + * @param info メモリ情報 + * @param msg メッセージ + */ +void DefaultMemoryListener::notifyError(const MemoryInfo& info, const std::string& msg) +{ + std::cerr << "MemoryError: " << msg << std::endl; + std::cerr << "\tat " << info.fileName << ":" << info.lineNumber << ":" << info.functionName + << " (size = " << info.size << ")" << std::endl; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理 +// + +/** + * メモリ管理. + * メモリの確保, 開放を行います. + * リスナを登録することで, メモリ確保, 開放, エラー発生時の通知を + * 受信することができます. + * + * 以下のようにメモリを管理しています. + * @code + * + * |<----管理メモリ------------->| + * +--------+--------------------+ + * |管理領域|ユーザ使用メモリ領域| + * +--------+--------------------+ + * ↑ユーザにはこの位置を返す + * + * c++ なので std::list 等を使っても良いが, + * list のメモリ確保でエラーがでると本末転倒なので, + * メモリ確保時に管理領域をまとめて確保&管理する. + * @endcode + * + */ +namespace MemoryManager +{ + + thread_local const char* fileName = ""; // 名前一時保存用 + thread_local int lineNumber = 0; // 行番号一時保存用 + thread_local const char* functionName = ""; // 関数名一時保存用 + + /** + * メモリの確保,開放,エラー発生の通知を受信するリスナを登録します. + * + * @param l リスナ + */ + void setListener(MemoryListener* l) + { + listener = l; + } + + + /** + * 管理している全メモリエントリを引数に指定されたハンドラを実行します. + * デフォルトで用意しているハンドラ printMemoryInfo を使用できます. + * + * @param handler ハンドラ + */ + void entries(void (*handler)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + handler(*info); + info = info->_next; + } + } + + + /** + * 指定されたメソッドが true を返す管理メモリをクリア(削除)します. + * 本メソッド実行時, 管理しているメモリの情報を引数に + * 指定された関数が実行されます. + * + * [注意事項] + * 本メソッドでメモリはクリアしますが, デストラクタは呼び出されないので注意 + * + * 使用例) + * @code + * bool isCleanup(const scpp::MemoryInfo& info) + * { // 管理しているメモリ全てクリアする + * return true; + * } + * scpp::MemoryManager::cleanup(&isCleanup); + * @endcode + * + * @param isCleanup クリアするか否かを返す関数ポインタ + */ + void cleanup(bool (*isCleanup)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + bool ret = isCleanup(*info); + if (ret) + { // クリア対象 + MemoryInfo* tmpInfo; + tmpInfo = info; + info = info->_next; + remove(tmpInfo); + tmpInfo->size = 0; + tmpInfo->_mark = MARK_DELETED; + free(tmpInfo); + } + else + { + info = info->_next; + } + } + } + + + /** + * 指定されたメモリの情報を出力します. + * + * @param info メモリの情報 + */ + void printMemoryInfo(const MemoryInfo& info) + { + std::cout << "[MemoryInfo] " + << info.fileName << ":" + << info.lineNumber << ":" + << info.functionName << " (size = " + << info.size << ")" + << std::endl; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル名 + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, int line, const char* func) + { + void* ptr = allocate(size, MARK_ALLOCATED, file, line, func); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param nmemb 確保するメモリの要素数 + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func) + { + std::size_t n = nmemb * size; + void* ptr = allocate(n, MARK_ALLOCATED, file, line, func); + if (ptr) + { // callc なのでゼロクリアする + memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * ポインタが示すメモリブロックのサイズを変更します. + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func) + { + if (ptr == 0) + { // ptr が null の場合, malloc と等価 + ptr = malloc(size, file, line, func); + return ptr; + } + + if (size == 0) + { // size が 0 の場合, free と等価 + free(ptr); + return 0; + } + + // メモリ管理領域を取得 + MemoryInfo* entry = static_cast (ptr); + entry--; + void* nptr = 0; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 管理メモリ + nptr = reallocate(entry, size, MARK_ALLOCATED, file, line, func, true); + break; + case MARK_DELETED: // 削除済みメモリ + nptr = malloc(size, file, line, func); + break; + case MARK_ALLOCATED_NEW: // new で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new : can't realloc"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new[] : can't realloc"); } + break; + default: // 管理対象外メモリ + nptr = reallocate(ptr, size, MARK_ALLOCATED, file, line, func, false); + } + + return nptr; + } + + + /** + * 指定されたメモリを開放します. + * + * @param ptr 開放するメモリへのポインタ + */ + void free(void* ptr) + { + MemoryInfo* entry; + if (ptr == 0) + { // null ポインタの場合なにもしない + return; + } + + // メモリ管理領域を取得 + entry = (MemoryInfo*) ptr; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 確保されたメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + + } + + +} // namespace MemoryManager +} // namespace scpp + diff --git a/modules/libscpp/bkup/scpp_memory.hpp b/modules/libscpp/bkup/scpp_memory.hpp new file mode 100644 index 0000000..675ab75 --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.hpp @@ -0,0 +1,129 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * メモリの確保/解放/エラー発生時に呼び出されるリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHandler メソッドにて登録することで、 + * メモリの確保/解放/エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager で管理しているメモリに対してのみ有効です。 + * (MemoryManager::malloc, MemoryManager::calloc, MemoryManager::realloc) + * + * new, malloc, calloc などを対象とする場合、 + * ENABLED_MEMORY_MANAGE を定義してください。 + */ + class MemoryListener + { + public: + virtual void notifyAlloc(const MemoryInfo& info) = 0; + virtual void notifyFree(const MemoryInfo& info) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + virtual ~MemoryListener() = 0; + }; + + + /** + * メモリ確保/解放/エラー発生時のデフォルト通知インタフェースです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener&) = delete; + void operator=(const DefaultMemoryListener&) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info); + virtual void notifyFree(const MemoryInfo& info); + virtual void notifyError(const MemoryInfo& info, const std::string& msg); + }; + + + /** + * メモリ管理。 + * メモリの確保、解放を行います。 + * ハンドラを登録することで、メモリの確保/解放/エラー時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* fileName; + extern thread_local int lineNumber; + extern thread_local const char* functionName; + + void setListener(MemoryListener* handler); + void entries(void (*handler)(const MemoryInfo& info)); + void cleanup(bool (*isCleanup)(const MemoryInfo& info)); + void printMemoryInfo(const MemoryInfo& info); + void* malloc( std::size_t size, const char* file, int line, const char* func); + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func); + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func); + void free(void* ptr); + } + +} + + +#if (ENABLED_MEMORY_MANAGE) +#if IS_SUPPORTED_CPP20 +#define SCPP_NODISCARD [[nodiscard]] +#else +#define SCPP_NODISCARD +#endif + +SCPP_NODISCARD void* operator new(std::size_t size); +SCPP_NODISCARD void* operator new[](std::size_t size); + +SCPP_NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +SCPP_NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; + +// void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; + +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; + +// 実質メモリ管理しないので除外 +// SCPP_NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; + +#if IS_SUPPORTED_CPP17 +// 以下、未サポート +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// +#endif + +#define new \ + ((scpp::MemoryManager::fileName = __FILE__, \ + scpp::MemoryManager::lineNumber = __LINE__, \ + scpp::MemoryManager::functionName = __func__, \ + 0) && 0) ? 0 : new + +#define malloc(size) scpp::MemoryManager::malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) scpp::MemoryManager::calloc(nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) scpp::MemoryManager::realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) scpp::MemoryManager::free(ptr) + +#endif // (ENABLED_MEMORY_MANAGE) + +#endif // SCPP_MEMORY_HPP diff --git a/modules/libscpp/bkup/scpp_unittest.hpp b/modules/libscpp/bkup/scpp_unittest.hpp new file mode 100644 index 0000000..9b2b154 --- /dev/null +++ b/modules/libscpp/bkup/scpp_unittest.hpp @@ -0,0 +1,11 @@ +/** + * @file scpp_unitteset.hpp + * @bried 単体テストモジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_UNITTEST_HPP +#define SCPP_UNITTEST_HPP + + +#endif // SCPP_UNITTEST_HPP diff --git a/modules/libscpp/include/scpp.hpp b/modules/libscpp/include/scpp.hpp new file mode 100644 index 0000000..00aaa98 --- /dev/null +++ b/modules/libscpp/include/scpp.hpp @@ -0,0 +1,15 @@ +/** + * @file scpp.hpp + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include +#include +#include + +#endif // SCPP_H + diff --git a/modules/libscpp/include/scpp_assert.hpp b/modules/libscpp/include/scpp_assert.hpp new file mode 100644 index 0000000..76aeb30 --- /dev/null +++ b/modules/libscpp/include/scpp_assert.hpp @@ -0,0 +1,24 @@ +/** + * @file scpp_assert.hpp + * @bried アサーションモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * アサーション関数が失敗するとき、エラーメッセージを出力します。 + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include +#include + +namespace scpp +{ + +/** + * アサーションに失敗した際に throw される Erro です。 + */ + + +#endif // SCPP_ASSERT_HPP + diff --git a/modules/libscpp/include/scpp_compiler.hpp b/modules/libscpp/include/scpp_compiler.hpp new file mode 100644 index 0000000..c56a6e2 --- /dev/null +++ b/modules/libscpp/include/scpp_compiler.hpp @@ -0,0 +1,42 @@ +/** + * @file scpp_compiler.hpp + * @bried C++言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C++言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + */ +#ifndef SCPP_COMPILER_H +#define SCPP_COMPILER_H +#ifdef __cplusplus + + +#if (__cplusplus >= 201103L) +/* ----- C++11 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (__cplusplus >= 202002L) +#define IS_SUPPORTED_CPP17 (__cplusplus >= 201703L) +#define IS_SUPPORTED_CPP14 (__cplusplus >= 201402L) +#define IS_SUPPORTED_CPP11 (__cplusplus >= 201103L) +#define IS_SUPPORTED_C17 (0) +#define IS_SUPPORTED_C11 (0) +#define IS_SUPPORTED_C99 (0) + +#else +/* ----- C++11 以前の場合はエラーとする */ +#error "unsupported c++ version, please use c++11 or later" + +#endif /* (__cplusplus >= 201103L) */ + + +#endif /* __cplusplus */ +#endif /* SCPP_COMPILER_H */ diff --git a/modules/libscpp/include/scpp_exception.hpp b/modules/libscpp/include/scpp_exception.hpp new file mode 100644 index 0000000..70df85f --- /dev/null +++ b/modules/libscpp/include/scpp_exception.hpp @@ -0,0 +1,77 @@ +/** + * @file scpp_exception.hpp + * @bried 例外クラス用ヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * 本ライブラリの例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ + class Throwable : public std::exception + { + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(Throwable&& t) noexcept; + Throwable(const std::string& msg) noexcept; + Throwable& operator=(const Throwable& t) noexcept; + Throwable& operator=(Throwable&& t) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; + }; + + + /** + * 本ライブラリの Exception クラス。 + * 本ライブラリにて発生したエラーのうち、回復可能なエラーは、 + * 本クラスを継承した Exception クラスを throw します。 + */ + class Exception : public Throwable + { + public: + Exception() noexcept; + Exception(const Exception& e) noexcept; + Exception(Exception&& e) noexcept; + Exception(const std::string& msg) noexcept; + Exception& operator=(const Exception& t) noexcept; + Exception& operator=(Exception&& t) noexcept; + virtual ~Exception() noexcept; + }; + + + /** + * 本ライブラリの Error クラス。 + * 本ライブラリにて発生したエラーのうち、回復困難なエラーは、 + * 本クラスを継承した Error クラスを throw します。 + */ + class Error : public Throwable + { + public: + Error() noexcept; + Error(const Error& t) noexcept; + Error(Error&& t) noexcept; + Error(const std::string& msg) noexcept; + Error& operator=(const Error& t) noexcept; + Error& operator=(Error&& t) noexcept; + virtual ~Error() noexcept; + }; + +} // namespace scpp + +#endif // SCPP_EXCEPTION_HPP + diff --git a/modules/libscpp/include/scpp_memory.hpp b/modules/libscpp/include/scpp_memory.hpp new file mode 100644 index 0000000..7a23506 --- /dev/null +++ b/modules/libscpp/include/scpp_memory.hpp @@ -0,0 +1,135 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include +#include + + +#include + +namespace scpp +{ + +#include + + typedef sc_memory MemoryInfo; + + + /** + * メモリが確保、解放、あるいはメモリ確保/解放時にエラーが発生した際のリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHander メソッドにて登録することで、 + * メモリの確保、解放、エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager にて管理しているメモリに対してのみ有効です。 + */ + class MemoryListener + { + public: + MemoryListener(); + MemoryListener(const MemoryListener& l) = delete; + MemoryListener& operator=(const MemoryListener& l) = delete; + virtual ~MemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyFree( const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + }; + + + /** + * メモリ確保、解放、メモリ確保/解放時にエラーが発生した際のデフォルトのリスナです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener& l) = delete; + DefaultMemoryListener& operator=(const DefaultMemoryListener& l) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyFree( const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + }; + + + /** + * メモリ管理。 + * メモリ確保、解放を行います。 + * ハンドラを登録することで、メモリ確保、解放、エラー発生時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* file; + extern thread_local int line; + extern thread_local const char* func; + + void setListener(MemoryListener& handler); + void entries(void (*handler)(const MemoryInfo& info)); + void freeif(bool (*handler)(const MemoryInfo& info)); + } + + +#if defined(SC_MEMORY_MANAGE) || defined(SCPP_MEMORY_MANAGE) + +#if (IS_SUPPORTED_CPP20) +// C++20 +#define NODISCARD [[nodiscard]] +#else +// C++20 以外 +#define NODISCARD +#endif + +// ----- C++11 ----- +NODISCARD void* operator new(std::size_t size); +NODISCARD void* operator new[](std::size_t size); +NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; +void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; +// 以下、実質メモリ管理しないため除外 +// NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; +// void operator delete(void* ptr, void*) noexcept; + +#if IS_SUPPORTED_CPP14 +// ----- C++14 ----- +void operator delete(void* ptr, std::size_t size) noexcept; +#endif + + +#if IS_SUPPORTED_CPP17 +// ----- C++17 ----- +// 現状未サポート [実装 +// NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +#endif // IS_SUPPORTED_CPP17 + +// ----- C++20 ----- +// C++11, C++17 の new に [[nodiscard]] が付与されている +// => マクロで対応済み + +// new の差し替え。 +// 先頭 +#define new \ + ((scpp::MemoryManager::file = __FILE__, \ + scpp::MemoryManager::line = __LINE__, \ + scpp::MemoryManager::func = __func__, \ + 0) && 0) ? 0 : new + +#endif // defined(SC_MEMORY_MANAGE) || defined(SCPP_MEMORY_MANAGE) + +} // namespace scpp + +#endif // SCPP_MEMORY_HPP diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/modules/libscpp/bkup/scpp_assert.hpp b/modules/libscpp/bkup/scpp_assert.hpp new file mode 100644 index 0000000..094836e --- /dev/null +++ b/modules/libscpp/bkup/scpp_assert.hpp @@ -0,0 +1,29 @@ +/** + * @file scpp_assert.hpp + * @bried Assert モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include + +namespace scpp +{ + + +class AssertError : public std::exception +{ + public: + AssertError() noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string% msg, +}; + + +} + + +#endif // SCPP_ASSERT_HPP diff --git a/modules/libscpp/bkup/scpp_exception.cpp b/modules/libscpp/bkup/scpp_exception.cpp new file mode 100644 index 0000000..5ed0c1c --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.cpp @@ -0,0 +1,13 @@ +/** + * @file scpp_exception.cpp + * @bried Exception モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + + +namespace scpp +{ +} + diff --git a/modules/libscpp/bkup/scpp_exception.hpp b/modules/libscpp/bkup/scpp_exception.hpp new file mode 100644 index 0000000..b37132f --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.hpp @@ -0,0 +1,65 @@ +/** + * @file scpp_exception.hpp + * @bried Exception モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + +/** + * 例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ +class Throwable: public std::exception +{ + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(const std::string& msg) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; +}; + + +/** + * 回復可能な例外クラス。 + */ +class Exception : public Throwable +{ + public: + Exception() noexcept; + Exception(const Throwable& t) noexcept; + Exception(const std::string& msg) noexcept; + virtual ~Exception() noexcept; +}; + + +/** + * 回復困難な例外クラス。 + */ +class Error : public Throwable +{ + public: + Error() noexcept; + Error(const Throwable& t) noexcept; + Error(const std::string& msg) noexcept; + virtual ~Error() noexcept; +}; + + +} + + +#endif // SCPP_EXCEPTION_HPP diff --git a/modules/libscpp/bkup/scpp_memory.cpp b/modules/libscpp/bkup/scpp_memory.cpp new file mode 100644 index 0000000..7213a9d --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.cpp @@ -0,0 +1,693 @@ +/** + * @file scpp_memory.cpp + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include +#include +#include +#include + + +// 本来の malloc, free を利用するため、ENABLED_MEMORY_MANAGE を無効にする +#ifdef ENABLED_MEMORY_MANAGE +#undef ENABLED_MEMORY_MANAGE +#endif +#include + + + +using namespace scpp; +namespace +{ + int const PADDING = sizeof(int) * 2; + int const MARK_ALLOCATED = 0x12340000; + int const MARK_ALLOCATED_NEW = 0x12341111; + int const MARK_ALLOCATED_NEW_ARRAY = 0x12342222; + int const MARK_DELETED = 0xFEDCBA00; + + bool infoIsInitialized = false; + std::mutex memMtx; //< 管理メモリ操作用 Mutex + MemoryInfo infoHead; //< 管理メモリ先頭 + MemoryInfo infoTail; //< 管理メモリ末尾 + MemoryInfo infoError; //< エラー発生時用 + MemoryListener* listener = 0; //< 通知リスナ + + // プロトタイプ宣言 + void init(); + void add(MemoryInfo* entry); + void remove(MemoryInfo* entry); + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func); + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng); + + /** + * new ハンドラを取得します。 + * + * @return new ハンドラ + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + /** + * メモリ管理初期化. + */ + void init() + { + if (!infoIsInitialized) + { + infoIsInitialized = true; + infoHead.fileName = infoTail.fileName = 0; + infoHead.lineNumber = infoTail.lineNumber = 0; + infoHead.functionName = infoTail.functionName = 0; + infoHead.size = infoTail.size = 0; + infoHead._prev = infoHead._next = &infoTail; + infoTail._prev = infoTail._next = &infoHead; + infoHead._mark = infoTail._mark = MARK_DELETED; + + // エラー処理用 + infoError.fileName = 0; + infoError.lineNumber = 0; + infoError.functionName = 0; + infoError.size = 0; + infoError._prev = 0; + infoError._next = 0; + infoError._mark = MARK_DELETED; + } + } + + + /** + * メモリエントリを追加します. + * + * @param entry 追加するエントリ + */ + void add(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + init(); + entry->_next = &infoTail; + entry->_prev = infoTail._prev; + infoTail._prev->_next = entry; + infoTail._prev = entry; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyAlloc(*entry); + } + } + + + /** + * メモリエントリを削除します. + * + * @param entry 削除するエントリ + */ + void remove(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyFree(*entry); + } + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func) + { + MemoryInfo* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast (::malloc(n + sizeof(MemoryInfo) + PADDING)); + if (entry != 0) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { + return 0; + } + } + + void* ptr = (entry + 1); + + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = ptr; + + // エントリに追加 + add(entry); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng) + { + if (isMng) + { // 管理メモリの場合, いったん削除 + remove(static_cast(ptr)); + } + + MemoryInfo* entry = static_cast (::realloc(ptr, n + sizeof(MemoryInfo) + PADDING)); + if (entry == 0) + { + // メモリ確保失敗 -> 元の領域は開放されないので再管理する + add(static_cast(ptr)); + errno = ENOMEM; + if (listener) + { // エラーハンドラが登録されている + infoError.size = n; + infoError.fileName = file; + infoError.lineNumber = line; + infoError.functionName = func; + listener->notifyError(infoError, "can't realloc"); + } + return 0; + } + + if (!isMng) + { // 管理対象外メモリの場合 + // |<---- 新たな確保領域 ---->| + // +----------+---------------+ + // |元々の領域|追加分+管理領域| + // +----------+---------------+ + // ↓ + // +--------+----------+------+ + // |管理領域|元々の領域|追加分| + // +--------+----------+------+ + memmove((entry + 1), entry, n); + } + + // 管理領域に情報を書き込む + void* nptr = (entry + 1); + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = nptr; + + // エントリに追加 + add(entry); + return nptr; + } + +} // namespace 無名 + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 以下, new / delete のオーバライド +// + + +void* operator new(std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new[](std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + +void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + + +void operator delete(void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } +} + +void operator delete(void* p, std::size_t) noexcept +{ + operator delete(p); +} + +void operator delete(void* p, const std::nothrow_t&) noexcept +{ + operator delete(p); +} + +void operator delete[](void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + +} + +void operator delete[](void* p, std::size_t) noexcept +{ + operator delete[](p); +} + +void operator delete[](void* p, const std::nothrow_t&) noexcept +{ + operator delete[](p); +} + + +namespace scpp +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// デフォルトのメモリ確保/開放時に実行されるリスナ +// + +DefaultMemoryListener::DefaultMemoryListener() +{ + // NOP +} +DefaultMemoryListener::~DefaultMemoryListener() +{ + // NOP +} + +/** + * メモリが確保された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyAlloc(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリが開放された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyFree(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリの確保/開放でエラーが発生した際に実行されるリスナ. + * エラー内容をエラー出力します. + * + * @param info メモリ情報 + * @param msg メッセージ + */ +void DefaultMemoryListener::notifyError(const MemoryInfo& info, const std::string& msg) +{ + std::cerr << "MemoryError: " << msg << std::endl; + std::cerr << "\tat " << info.fileName << ":" << info.lineNumber << ":" << info.functionName + << " (size = " << info.size << ")" << std::endl; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理 +// + +/** + * メモリ管理. + * メモリの確保, 開放を行います. + * リスナを登録することで, メモリ確保, 開放, エラー発生時の通知を + * 受信することができます. + * + * 以下のようにメモリを管理しています. + * @code + * + * |<----管理メモリ------------->| + * +--------+--------------------+ + * |管理領域|ユーザ使用メモリ領域| + * +--------+--------------------+ + * ↑ユーザにはこの位置を返す + * + * c++ なので std::list 等を使っても良いが, + * list のメモリ確保でエラーがでると本末転倒なので, + * メモリ確保時に管理領域をまとめて確保&管理する. + * @endcode + * + */ +namespace MemoryManager +{ + + thread_local const char* fileName = ""; // 名前一時保存用 + thread_local int lineNumber = 0; // 行番号一時保存用 + thread_local const char* functionName = ""; // 関数名一時保存用 + + /** + * メモリの確保,開放,エラー発生の通知を受信するリスナを登録します. + * + * @param l リスナ + */ + void setListener(MemoryListener* l) + { + listener = l; + } + + + /** + * 管理している全メモリエントリを引数に指定されたハンドラを実行します. + * デフォルトで用意しているハンドラ printMemoryInfo を使用できます. + * + * @param handler ハンドラ + */ + void entries(void (*handler)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + handler(*info); + info = info->_next; + } + } + + + /** + * 指定されたメソッドが true を返す管理メモリをクリア(削除)します. + * 本メソッド実行時, 管理しているメモリの情報を引数に + * 指定された関数が実行されます. + * + * [注意事項] + * 本メソッドでメモリはクリアしますが, デストラクタは呼び出されないので注意 + * + * 使用例) + * @code + * bool isCleanup(const scpp::MemoryInfo& info) + * { // 管理しているメモリ全てクリアする + * return true; + * } + * scpp::MemoryManager::cleanup(&isCleanup); + * @endcode + * + * @param isCleanup クリアするか否かを返す関数ポインタ + */ + void cleanup(bool (*isCleanup)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + bool ret = isCleanup(*info); + if (ret) + { // クリア対象 + MemoryInfo* tmpInfo; + tmpInfo = info; + info = info->_next; + remove(tmpInfo); + tmpInfo->size = 0; + tmpInfo->_mark = MARK_DELETED; + free(tmpInfo); + } + else + { + info = info->_next; + } + } + } + + + /** + * 指定されたメモリの情報を出力します. + * + * @param info メモリの情報 + */ + void printMemoryInfo(const MemoryInfo& info) + { + std::cout << "[MemoryInfo] " + << info.fileName << ":" + << info.lineNumber << ":" + << info.functionName << " (size = " + << info.size << ")" + << std::endl; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル名 + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, int line, const char* func) + { + void* ptr = allocate(size, MARK_ALLOCATED, file, line, func); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param nmemb 確保するメモリの要素数 + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func) + { + std::size_t n = nmemb * size; + void* ptr = allocate(n, MARK_ALLOCATED, file, line, func); + if (ptr) + { // callc なのでゼロクリアする + memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * ポインタが示すメモリブロックのサイズを変更します. + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func) + { + if (ptr == 0) + { // ptr が null の場合, malloc と等価 + ptr = malloc(size, file, line, func); + return ptr; + } + + if (size == 0) + { // size が 0 の場合, free と等価 + free(ptr); + return 0; + } + + // メモリ管理領域を取得 + MemoryInfo* entry = static_cast (ptr); + entry--; + void* nptr = 0; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 管理メモリ + nptr = reallocate(entry, size, MARK_ALLOCATED, file, line, func, true); + break; + case MARK_DELETED: // 削除済みメモリ + nptr = malloc(size, file, line, func); + break; + case MARK_ALLOCATED_NEW: // new で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new : can't realloc"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new[] : can't realloc"); } + break; + default: // 管理対象外メモリ + nptr = reallocate(ptr, size, MARK_ALLOCATED, file, line, func, false); + } + + return nptr; + } + + + /** + * 指定されたメモリを開放します. + * + * @param ptr 開放するメモリへのポインタ + */ + void free(void* ptr) + { + MemoryInfo* entry; + if (ptr == 0) + { // null ポインタの場合なにもしない + return; + } + + // メモリ管理領域を取得 + entry = (MemoryInfo*) ptr; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 確保されたメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + + } + + +} // namespace MemoryManager +} // namespace scpp + diff --git a/modules/libscpp/bkup/scpp_memory.hpp b/modules/libscpp/bkup/scpp_memory.hpp new file mode 100644 index 0000000..675ab75 --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.hpp @@ -0,0 +1,129 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * メモリの確保/解放/エラー発生時に呼び出されるリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHandler メソッドにて登録することで、 + * メモリの確保/解放/エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager で管理しているメモリに対してのみ有効です。 + * (MemoryManager::malloc, MemoryManager::calloc, MemoryManager::realloc) + * + * new, malloc, calloc などを対象とする場合、 + * ENABLED_MEMORY_MANAGE を定義してください。 + */ + class MemoryListener + { + public: + virtual void notifyAlloc(const MemoryInfo& info) = 0; + virtual void notifyFree(const MemoryInfo& info) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + virtual ~MemoryListener() = 0; + }; + + + /** + * メモリ確保/解放/エラー発生時のデフォルト通知インタフェースです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener&) = delete; + void operator=(const DefaultMemoryListener&) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info); + virtual void notifyFree(const MemoryInfo& info); + virtual void notifyError(const MemoryInfo& info, const std::string& msg); + }; + + + /** + * メモリ管理。 + * メモリの確保、解放を行います。 + * ハンドラを登録することで、メモリの確保/解放/エラー時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* fileName; + extern thread_local int lineNumber; + extern thread_local const char* functionName; + + void setListener(MemoryListener* handler); + void entries(void (*handler)(const MemoryInfo& info)); + void cleanup(bool (*isCleanup)(const MemoryInfo& info)); + void printMemoryInfo(const MemoryInfo& info); + void* malloc( std::size_t size, const char* file, int line, const char* func); + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func); + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func); + void free(void* ptr); + } + +} + + +#if (ENABLED_MEMORY_MANAGE) +#if IS_SUPPORTED_CPP20 +#define SCPP_NODISCARD [[nodiscard]] +#else +#define SCPP_NODISCARD +#endif + +SCPP_NODISCARD void* operator new(std::size_t size); +SCPP_NODISCARD void* operator new[](std::size_t size); + +SCPP_NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +SCPP_NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; + +// void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; + +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; + +// 実質メモリ管理しないので除外 +// SCPP_NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; + +#if IS_SUPPORTED_CPP17 +// 以下、未サポート +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// +#endif + +#define new \ + ((scpp::MemoryManager::fileName = __FILE__, \ + scpp::MemoryManager::lineNumber = __LINE__, \ + scpp::MemoryManager::functionName = __func__, \ + 0) && 0) ? 0 : new + +#define malloc(size) scpp::MemoryManager::malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) scpp::MemoryManager::calloc(nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) scpp::MemoryManager::realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) scpp::MemoryManager::free(ptr) + +#endif // (ENABLED_MEMORY_MANAGE) + +#endif // SCPP_MEMORY_HPP diff --git a/modules/libscpp/bkup/scpp_unittest.hpp b/modules/libscpp/bkup/scpp_unittest.hpp new file mode 100644 index 0000000..9b2b154 --- /dev/null +++ b/modules/libscpp/bkup/scpp_unittest.hpp @@ -0,0 +1,11 @@ +/** + * @file scpp_unitteset.hpp + * @bried 単体テストモジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_UNITTEST_HPP +#define SCPP_UNITTEST_HPP + + +#endif // SCPP_UNITTEST_HPP diff --git a/modules/libscpp/include/scpp.hpp b/modules/libscpp/include/scpp.hpp new file mode 100644 index 0000000..00aaa98 --- /dev/null +++ b/modules/libscpp/include/scpp.hpp @@ -0,0 +1,15 @@ +/** + * @file scpp.hpp + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include +#include +#include + +#endif // SCPP_H + diff --git a/modules/libscpp/include/scpp_assert.hpp b/modules/libscpp/include/scpp_assert.hpp new file mode 100644 index 0000000..76aeb30 --- /dev/null +++ b/modules/libscpp/include/scpp_assert.hpp @@ -0,0 +1,24 @@ +/** + * @file scpp_assert.hpp + * @bried アサーションモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * アサーション関数が失敗するとき、エラーメッセージを出力します。 + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include +#include + +namespace scpp +{ + +/** + * アサーションに失敗した際に throw される Erro です。 + */ + + +#endif // SCPP_ASSERT_HPP + diff --git a/modules/libscpp/include/scpp_compiler.hpp b/modules/libscpp/include/scpp_compiler.hpp new file mode 100644 index 0000000..c56a6e2 --- /dev/null +++ b/modules/libscpp/include/scpp_compiler.hpp @@ -0,0 +1,42 @@ +/** + * @file scpp_compiler.hpp + * @bried C++言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C++言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + */ +#ifndef SCPP_COMPILER_H +#define SCPP_COMPILER_H +#ifdef __cplusplus + + +#if (__cplusplus >= 201103L) +/* ----- C++11 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (__cplusplus >= 202002L) +#define IS_SUPPORTED_CPP17 (__cplusplus >= 201703L) +#define IS_SUPPORTED_CPP14 (__cplusplus >= 201402L) +#define IS_SUPPORTED_CPP11 (__cplusplus >= 201103L) +#define IS_SUPPORTED_C17 (0) +#define IS_SUPPORTED_C11 (0) +#define IS_SUPPORTED_C99 (0) + +#else +/* ----- C++11 以前の場合はエラーとする */ +#error "unsupported c++ version, please use c++11 or later" + +#endif /* (__cplusplus >= 201103L) */ + + +#endif /* __cplusplus */ +#endif /* SCPP_COMPILER_H */ diff --git a/modules/libscpp/include/scpp_exception.hpp b/modules/libscpp/include/scpp_exception.hpp new file mode 100644 index 0000000..70df85f --- /dev/null +++ b/modules/libscpp/include/scpp_exception.hpp @@ -0,0 +1,77 @@ +/** + * @file scpp_exception.hpp + * @bried 例外クラス用ヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * 本ライブラリの例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ + class Throwable : public std::exception + { + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(Throwable&& t) noexcept; + Throwable(const std::string& msg) noexcept; + Throwable& operator=(const Throwable& t) noexcept; + Throwable& operator=(Throwable&& t) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; + }; + + + /** + * 本ライブラリの Exception クラス。 + * 本ライブラリにて発生したエラーのうち、回復可能なエラーは、 + * 本クラスを継承した Exception クラスを throw します。 + */ + class Exception : public Throwable + { + public: + Exception() noexcept; + Exception(const Exception& e) noexcept; + Exception(Exception&& e) noexcept; + Exception(const std::string& msg) noexcept; + Exception& operator=(const Exception& t) noexcept; + Exception& operator=(Exception&& t) noexcept; + virtual ~Exception() noexcept; + }; + + + /** + * 本ライブラリの Error クラス。 + * 本ライブラリにて発生したエラーのうち、回復困難なエラーは、 + * 本クラスを継承した Error クラスを throw します。 + */ + class Error : public Throwable + { + public: + Error() noexcept; + Error(const Error& t) noexcept; + Error(Error&& t) noexcept; + Error(const std::string& msg) noexcept; + Error& operator=(const Error& t) noexcept; + Error& operator=(Error&& t) noexcept; + virtual ~Error() noexcept; + }; + +} // namespace scpp + +#endif // SCPP_EXCEPTION_HPP + diff --git a/modules/libscpp/include/scpp_memory.hpp b/modules/libscpp/include/scpp_memory.hpp new file mode 100644 index 0000000..7a23506 --- /dev/null +++ b/modules/libscpp/include/scpp_memory.hpp @@ -0,0 +1,135 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include +#include + + +#include + +namespace scpp +{ + +#include + + typedef sc_memory MemoryInfo; + + + /** + * メモリが確保、解放、あるいはメモリ確保/解放時にエラーが発生した際のリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHander メソッドにて登録することで、 + * メモリの確保、解放、エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager にて管理しているメモリに対してのみ有効です。 + */ + class MemoryListener + { + public: + MemoryListener(); + MemoryListener(const MemoryListener& l) = delete; + MemoryListener& operator=(const MemoryListener& l) = delete; + virtual ~MemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyFree( const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + }; + + + /** + * メモリ確保、解放、メモリ確保/解放時にエラーが発生した際のデフォルトのリスナです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener& l) = delete; + DefaultMemoryListener& operator=(const DefaultMemoryListener& l) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyFree( const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + }; + + + /** + * メモリ管理。 + * メモリ確保、解放を行います。 + * ハンドラを登録することで、メモリ確保、解放、エラー発生時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* file; + extern thread_local int line; + extern thread_local const char* func; + + void setListener(MemoryListener& handler); + void entries(void (*handler)(const MemoryInfo& info)); + void freeif(bool (*handler)(const MemoryInfo& info)); + } + + +#if defined(SC_MEMORY_MANAGE) || defined(SCPP_MEMORY_MANAGE) + +#if (IS_SUPPORTED_CPP20) +// C++20 +#define NODISCARD [[nodiscard]] +#else +// C++20 以外 +#define NODISCARD +#endif + +// ----- C++11 ----- +NODISCARD void* operator new(std::size_t size); +NODISCARD void* operator new[](std::size_t size); +NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; +void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; +// 以下、実質メモリ管理しないため除外 +// NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; +// void operator delete(void* ptr, void*) noexcept; + +#if IS_SUPPORTED_CPP14 +// ----- C++14 ----- +void operator delete(void* ptr, std::size_t size) noexcept; +#endif + + +#if IS_SUPPORTED_CPP17 +// ----- C++17 ----- +// 現状未サポート [実装 +// NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +#endif // IS_SUPPORTED_CPP17 + +// ----- C++20 ----- +// C++11, C++17 の new に [[nodiscard]] が付与されている +// => マクロで対応済み + +// new の差し替え。 +// 先頭 +#define new \ + ((scpp::MemoryManager::file = __FILE__, \ + scpp::MemoryManager::line = __LINE__, \ + scpp::MemoryManager::func = __func__, \ + 0) && 0) ? 0 : new + +#endif // defined(SC_MEMORY_MANAGE) || defined(SCPP_MEMORY_MANAGE) + +} // namespace scpp + +#endif // SCPP_MEMORY_HPP diff --git a/modules/libscpp/include/scpp_unittest.hpp b/modules/libscpp/include/scpp_unittest.hpp new file mode 100644 index 0000000..038f7ab --- /dev/null +++ b/modules/libscpp/include/scpp_unittest.hpp @@ -0,0 +1,15 @@ +/** + * @file scpp_unittest.hpp + * @bried 簡易単体テスト用ヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_UNITTEST_HPP +#define SCPP_UNITTEST_HPP + + +#include + + +#endif // SCPP_UNITTEST_HPP + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/modules/libscpp/bkup/scpp_assert.hpp b/modules/libscpp/bkup/scpp_assert.hpp new file mode 100644 index 0000000..094836e --- /dev/null +++ b/modules/libscpp/bkup/scpp_assert.hpp @@ -0,0 +1,29 @@ +/** + * @file scpp_assert.hpp + * @bried Assert モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include + +namespace scpp +{ + + +class AssertError : public std::exception +{ + public: + AssertError() noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string% msg, +}; + + +} + + +#endif // SCPP_ASSERT_HPP diff --git a/modules/libscpp/bkup/scpp_exception.cpp b/modules/libscpp/bkup/scpp_exception.cpp new file mode 100644 index 0000000..5ed0c1c --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.cpp @@ -0,0 +1,13 @@ +/** + * @file scpp_exception.cpp + * @bried Exception モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + + +namespace scpp +{ +} + diff --git a/modules/libscpp/bkup/scpp_exception.hpp b/modules/libscpp/bkup/scpp_exception.hpp new file mode 100644 index 0000000..b37132f --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.hpp @@ -0,0 +1,65 @@ +/** + * @file scpp_exception.hpp + * @bried Exception モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + +/** + * 例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ +class Throwable: public std::exception +{ + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(const std::string& msg) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; +}; + + +/** + * 回復可能な例外クラス。 + */ +class Exception : public Throwable +{ + public: + Exception() noexcept; + Exception(const Throwable& t) noexcept; + Exception(const std::string& msg) noexcept; + virtual ~Exception() noexcept; +}; + + +/** + * 回復困難な例外クラス。 + */ +class Error : public Throwable +{ + public: + Error() noexcept; + Error(const Throwable& t) noexcept; + Error(const std::string& msg) noexcept; + virtual ~Error() noexcept; +}; + + +} + + +#endif // SCPP_EXCEPTION_HPP diff --git a/modules/libscpp/bkup/scpp_memory.cpp b/modules/libscpp/bkup/scpp_memory.cpp new file mode 100644 index 0000000..7213a9d --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.cpp @@ -0,0 +1,693 @@ +/** + * @file scpp_memory.cpp + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include +#include +#include +#include + + +// 本来の malloc, free を利用するため、ENABLED_MEMORY_MANAGE を無効にする +#ifdef ENABLED_MEMORY_MANAGE +#undef ENABLED_MEMORY_MANAGE +#endif +#include + + + +using namespace scpp; +namespace +{ + int const PADDING = sizeof(int) * 2; + int const MARK_ALLOCATED = 0x12340000; + int const MARK_ALLOCATED_NEW = 0x12341111; + int const MARK_ALLOCATED_NEW_ARRAY = 0x12342222; + int const MARK_DELETED = 0xFEDCBA00; + + bool infoIsInitialized = false; + std::mutex memMtx; //< 管理メモリ操作用 Mutex + MemoryInfo infoHead; //< 管理メモリ先頭 + MemoryInfo infoTail; //< 管理メモリ末尾 + MemoryInfo infoError; //< エラー発生時用 + MemoryListener* listener = 0; //< 通知リスナ + + // プロトタイプ宣言 + void init(); + void add(MemoryInfo* entry); + void remove(MemoryInfo* entry); + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func); + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng); + + /** + * new ハンドラを取得します。 + * + * @return new ハンドラ + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + /** + * メモリ管理初期化. + */ + void init() + { + if (!infoIsInitialized) + { + infoIsInitialized = true; + infoHead.fileName = infoTail.fileName = 0; + infoHead.lineNumber = infoTail.lineNumber = 0; + infoHead.functionName = infoTail.functionName = 0; + infoHead.size = infoTail.size = 0; + infoHead._prev = infoHead._next = &infoTail; + infoTail._prev = infoTail._next = &infoHead; + infoHead._mark = infoTail._mark = MARK_DELETED; + + // エラー処理用 + infoError.fileName = 0; + infoError.lineNumber = 0; + infoError.functionName = 0; + infoError.size = 0; + infoError._prev = 0; + infoError._next = 0; + infoError._mark = MARK_DELETED; + } + } + + + /** + * メモリエントリを追加します. + * + * @param entry 追加するエントリ + */ + void add(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + init(); + entry->_next = &infoTail; + entry->_prev = infoTail._prev; + infoTail._prev->_next = entry; + infoTail._prev = entry; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyAlloc(*entry); + } + } + + + /** + * メモリエントリを削除します. + * + * @param entry 削除するエントリ + */ + void remove(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyFree(*entry); + } + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func) + { + MemoryInfo* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast (::malloc(n + sizeof(MemoryInfo) + PADDING)); + if (entry != 0) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { + return 0; + } + } + + void* ptr = (entry + 1); + + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = ptr; + + // エントリに追加 + add(entry); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng) + { + if (isMng) + { // 管理メモリの場合, いったん削除 + remove(static_cast(ptr)); + } + + MemoryInfo* entry = static_cast (::realloc(ptr, n + sizeof(MemoryInfo) + PADDING)); + if (entry == 0) + { + // メモリ確保失敗 -> 元の領域は開放されないので再管理する + add(static_cast(ptr)); + errno = ENOMEM; + if (listener) + { // エラーハンドラが登録されている + infoError.size = n; + infoError.fileName = file; + infoError.lineNumber = line; + infoError.functionName = func; + listener->notifyError(infoError, "can't realloc"); + } + return 0; + } + + if (!isMng) + { // 管理対象外メモリの場合 + // |<---- 新たな確保領域 ---->| + // +----------+---------------+ + // |元々の領域|追加分+管理領域| + // +----------+---------------+ + // ↓ + // +--------+----------+------+ + // |管理領域|元々の領域|追加分| + // +--------+----------+------+ + memmove((entry + 1), entry, n); + } + + // 管理領域に情報を書き込む + void* nptr = (entry + 1); + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = nptr; + + // エントリに追加 + add(entry); + return nptr; + } + +} // namespace 無名 + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 以下, new / delete のオーバライド +// + + +void* operator new(std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new[](std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + +void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + + +void operator delete(void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } +} + +void operator delete(void* p, std::size_t) noexcept +{ + operator delete(p); +} + +void operator delete(void* p, const std::nothrow_t&) noexcept +{ + operator delete(p); +} + +void operator delete[](void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + +} + +void operator delete[](void* p, std::size_t) noexcept +{ + operator delete[](p); +} + +void operator delete[](void* p, const std::nothrow_t&) noexcept +{ + operator delete[](p); +} + + +namespace scpp +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// デフォルトのメモリ確保/開放時に実行されるリスナ +// + +DefaultMemoryListener::DefaultMemoryListener() +{ + // NOP +} +DefaultMemoryListener::~DefaultMemoryListener() +{ + // NOP +} + +/** + * メモリが確保された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyAlloc(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリが開放された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyFree(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリの確保/開放でエラーが発生した際に実行されるリスナ. + * エラー内容をエラー出力します. + * + * @param info メモリ情報 + * @param msg メッセージ + */ +void DefaultMemoryListener::notifyError(const MemoryInfo& info, const std::string& msg) +{ + std::cerr << "MemoryError: " << msg << std::endl; + std::cerr << "\tat " << info.fileName << ":" << info.lineNumber << ":" << info.functionName + << " (size = " << info.size << ")" << std::endl; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理 +// + +/** + * メモリ管理. + * メモリの確保, 開放を行います. + * リスナを登録することで, メモリ確保, 開放, エラー発生時の通知を + * 受信することができます. + * + * 以下のようにメモリを管理しています. + * @code + * + * |<----管理メモリ------------->| + * +--------+--------------------+ + * |管理領域|ユーザ使用メモリ領域| + * +--------+--------------------+ + * ↑ユーザにはこの位置を返す + * + * c++ なので std::list 等を使っても良いが, + * list のメモリ確保でエラーがでると本末転倒なので, + * メモリ確保時に管理領域をまとめて確保&管理する. + * @endcode + * + */ +namespace MemoryManager +{ + + thread_local const char* fileName = ""; // 名前一時保存用 + thread_local int lineNumber = 0; // 行番号一時保存用 + thread_local const char* functionName = ""; // 関数名一時保存用 + + /** + * メモリの確保,開放,エラー発生の通知を受信するリスナを登録します. + * + * @param l リスナ + */ + void setListener(MemoryListener* l) + { + listener = l; + } + + + /** + * 管理している全メモリエントリを引数に指定されたハンドラを実行します. + * デフォルトで用意しているハンドラ printMemoryInfo を使用できます. + * + * @param handler ハンドラ + */ + void entries(void (*handler)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + handler(*info); + info = info->_next; + } + } + + + /** + * 指定されたメソッドが true を返す管理メモリをクリア(削除)します. + * 本メソッド実行時, 管理しているメモリの情報を引数に + * 指定された関数が実行されます. + * + * [注意事項] + * 本メソッドでメモリはクリアしますが, デストラクタは呼び出されないので注意 + * + * 使用例) + * @code + * bool isCleanup(const scpp::MemoryInfo& info) + * { // 管理しているメモリ全てクリアする + * return true; + * } + * scpp::MemoryManager::cleanup(&isCleanup); + * @endcode + * + * @param isCleanup クリアするか否かを返す関数ポインタ + */ + void cleanup(bool (*isCleanup)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + bool ret = isCleanup(*info); + if (ret) + { // クリア対象 + MemoryInfo* tmpInfo; + tmpInfo = info; + info = info->_next; + remove(tmpInfo); + tmpInfo->size = 0; + tmpInfo->_mark = MARK_DELETED; + free(tmpInfo); + } + else + { + info = info->_next; + } + } + } + + + /** + * 指定されたメモリの情報を出力します. + * + * @param info メモリの情報 + */ + void printMemoryInfo(const MemoryInfo& info) + { + std::cout << "[MemoryInfo] " + << info.fileName << ":" + << info.lineNumber << ":" + << info.functionName << " (size = " + << info.size << ")" + << std::endl; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル名 + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, int line, const char* func) + { + void* ptr = allocate(size, MARK_ALLOCATED, file, line, func); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param nmemb 確保するメモリの要素数 + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func) + { + std::size_t n = nmemb * size; + void* ptr = allocate(n, MARK_ALLOCATED, file, line, func); + if (ptr) + { // callc なのでゼロクリアする + memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * ポインタが示すメモリブロックのサイズを変更します. + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func) + { + if (ptr == 0) + { // ptr が null の場合, malloc と等価 + ptr = malloc(size, file, line, func); + return ptr; + } + + if (size == 0) + { // size が 0 の場合, free と等価 + free(ptr); + return 0; + } + + // メモリ管理領域を取得 + MemoryInfo* entry = static_cast (ptr); + entry--; + void* nptr = 0; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 管理メモリ + nptr = reallocate(entry, size, MARK_ALLOCATED, file, line, func, true); + break; + case MARK_DELETED: // 削除済みメモリ + nptr = malloc(size, file, line, func); + break; + case MARK_ALLOCATED_NEW: // new で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new : can't realloc"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new[] : can't realloc"); } + break; + default: // 管理対象外メモリ + nptr = reallocate(ptr, size, MARK_ALLOCATED, file, line, func, false); + } + + return nptr; + } + + + /** + * 指定されたメモリを開放します. + * + * @param ptr 開放するメモリへのポインタ + */ + void free(void* ptr) + { + MemoryInfo* entry; + if (ptr == 0) + { // null ポインタの場合なにもしない + return; + } + + // メモリ管理領域を取得 + entry = (MemoryInfo*) ptr; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 確保されたメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + + } + + +} // namespace MemoryManager +} // namespace scpp + diff --git a/modules/libscpp/bkup/scpp_memory.hpp b/modules/libscpp/bkup/scpp_memory.hpp new file mode 100644 index 0000000..675ab75 --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.hpp @@ -0,0 +1,129 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * メモリの確保/解放/エラー発生時に呼び出されるリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHandler メソッドにて登録することで、 + * メモリの確保/解放/エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager で管理しているメモリに対してのみ有効です。 + * (MemoryManager::malloc, MemoryManager::calloc, MemoryManager::realloc) + * + * new, malloc, calloc などを対象とする場合、 + * ENABLED_MEMORY_MANAGE を定義してください。 + */ + class MemoryListener + { + public: + virtual void notifyAlloc(const MemoryInfo& info) = 0; + virtual void notifyFree(const MemoryInfo& info) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + virtual ~MemoryListener() = 0; + }; + + + /** + * メモリ確保/解放/エラー発生時のデフォルト通知インタフェースです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener&) = delete; + void operator=(const DefaultMemoryListener&) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info); + virtual void notifyFree(const MemoryInfo& info); + virtual void notifyError(const MemoryInfo& info, const std::string& msg); + }; + + + /** + * メモリ管理。 + * メモリの確保、解放を行います。 + * ハンドラを登録することで、メモリの確保/解放/エラー時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* fileName; + extern thread_local int lineNumber; + extern thread_local const char* functionName; + + void setListener(MemoryListener* handler); + void entries(void (*handler)(const MemoryInfo& info)); + void cleanup(bool (*isCleanup)(const MemoryInfo& info)); + void printMemoryInfo(const MemoryInfo& info); + void* malloc( std::size_t size, const char* file, int line, const char* func); + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func); + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func); + void free(void* ptr); + } + +} + + +#if (ENABLED_MEMORY_MANAGE) +#if IS_SUPPORTED_CPP20 +#define SCPP_NODISCARD [[nodiscard]] +#else +#define SCPP_NODISCARD +#endif + +SCPP_NODISCARD void* operator new(std::size_t size); +SCPP_NODISCARD void* operator new[](std::size_t size); + +SCPP_NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +SCPP_NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; + +// void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; + +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; + +// 実質メモリ管理しないので除外 +// SCPP_NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; + +#if IS_SUPPORTED_CPP17 +// 以下、未サポート +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// +#endif + +#define new \ + ((scpp::MemoryManager::fileName = __FILE__, \ + scpp::MemoryManager::lineNumber = __LINE__, \ + scpp::MemoryManager::functionName = __func__, \ + 0) && 0) ? 0 : new + +#define malloc(size) scpp::MemoryManager::malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) scpp::MemoryManager::calloc(nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) scpp::MemoryManager::realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) scpp::MemoryManager::free(ptr) + +#endif // (ENABLED_MEMORY_MANAGE) + +#endif // SCPP_MEMORY_HPP diff --git a/modules/libscpp/bkup/scpp_unittest.hpp b/modules/libscpp/bkup/scpp_unittest.hpp new file mode 100644 index 0000000..9b2b154 --- /dev/null +++ b/modules/libscpp/bkup/scpp_unittest.hpp @@ -0,0 +1,11 @@ +/** + * @file scpp_unitteset.hpp + * @bried 単体テストモジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_UNITTEST_HPP +#define SCPP_UNITTEST_HPP + + +#endif // SCPP_UNITTEST_HPP diff --git a/modules/libscpp/include/scpp.hpp b/modules/libscpp/include/scpp.hpp new file mode 100644 index 0000000..00aaa98 --- /dev/null +++ b/modules/libscpp/include/scpp.hpp @@ -0,0 +1,15 @@ +/** + * @file scpp.hpp + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include +#include +#include + +#endif // SCPP_H + diff --git a/modules/libscpp/include/scpp_assert.hpp b/modules/libscpp/include/scpp_assert.hpp new file mode 100644 index 0000000..76aeb30 --- /dev/null +++ b/modules/libscpp/include/scpp_assert.hpp @@ -0,0 +1,24 @@ +/** + * @file scpp_assert.hpp + * @bried アサーションモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * アサーション関数が失敗するとき、エラーメッセージを出力します。 + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include +#include + +namespace scpp +{ + +/** + * アサーションに失敗した際に throw される Erro です。 + */ + + +#endif // SCPP_ASSERT_HPP + diff --git a/modules/libscpp/include/scpp_compiler.hpp b/modules/libscpp/include/scpp_compiler.hpp new file mode 100644 index 0000000..c56a6e2 --- /dev/null +++ b/modules/libscpp/include/scpp_compiler.hpp @@ -0,0 +1,42 @@ +/** + * @file scpp_compiler.hpp + * @bried C++言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C++言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + */ +#ifndef SCPP_COMPILER_H +#define SCPP_COMPILER_H +#ifdef __cplusplus + + +#if (__cplusplus >= 201103L) +/* ----- C++11 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (__cplusplus >= 202002L) +#define IS_SUPPORTED_CPP17 (__cplusplus >= 201703L) +#define IS_SUPPORTED_CPP14 (__cplusplus >= 201402L) +#define IS_SUPPORTED_CPP11 (__cplusplus >= 201103L) +#define IS_SUPPORTED_C17 (0) +#define IS_SUPPORTED_C11 (0) +#define IS_SUPPORTED_C99 (0) + +#else +/* ----- C++11 以前の場合はエラーとする */ +#error "unsupported c++ version, please use c++11 or later" + +#endif /* (__cplusplus >= 201103L) */ + + +#endif /* __cplusplus */ +#endif /* SCPP_COMPILER_H */ diff --git a/modules/libscpp/include/scpp_exception.hpp b/modules/libscpp/include/scpp_exception.hpp new file mode 100644 index 0000000..70df85f --- /dev/null +++ b/modules/libscpp/include/scpp_exception.hpp @@ -0,0 +1,77 @@ +/** + * @file scpp_exception.hpp + * @bried 例外クラス用ヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * 本ライブラリの例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ + class Throwable : public std::exception + { + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(Throwable&& t) noexcept; + Throwable(const std::string& msg) noexcept; + Throwable& operator=(const Throwable& t) noexcept; + Throwable& operator=(Throwable&& t) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; + }; + + + /** + * 本ライブラリの Exception クラス。 + * 本ライブラリにて発生したエラーのうち、回復可能なエラーは、 + * 本クラスを継承した Exception クラスを throw します。 + */ + class Exception : public Throwable + { + public: + Exception() noexcept; + Exception(const Exception& e) noexcept; + Exception(Exception&& e) noexcept; + Exception(const std::string& msg) noexcept; + Exception& operator=(const Exception& t) noexcept; + Exception& operator=(Exception&& t) noexcept; + virtual ~Exception() noexcept; + }; + + + /** + * 本ライブラリの Error クラス。 + * 本ライブラリにて発生したエラーのうち、回復困難なエラーは、 + * 本クラスを継承した Error クラスを throw します。 + */ + class Error : public Throwable + { + public: + Error() noexcept; + Error(const Error& t) noexcept; + Error(Error&& t) noexcept; + Error(const std::string& msg) noexcept; + Error& operator=(const Error& t) noexcept; + Error& operator=(Error&& t) noexcept; + virtual ~Error() noexcept; + }; + +} // namespace scpp + +#endif // SCPP_EXCEPTION_HPP + diff --git a/modules/libscpp/include/scpp_memory.hpp b/modules/libscpp/include/scpp_memory.hpp new file mode 100644 index 0000000..7a23506 --- /dev/null +++ b/modules/libscpp/include/scpp_memory.hpp @@ -0,0 +1,135 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include +#include + + +#include + +namespace scpp +{ + +#include + + typedef sc_memory MemoryInfo; + + + /** + * メモリが確保、解放、あるいはメモリ確保/解放時にエラーが発生した際のリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHander メソッドにて登録することで、 + * メモリの確保、解放、エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager にて管理しているメモリに対してのみ有効です。 + */ + class MemoryListener + { + public: + MemoryListener(); + MemoryListener(const MemoryListener& l) = delete; + MemoryListener& operator=(const MemoryListener& l) = delete; + virtual ~MemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyFree( const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + }; + + + /** + * メモリ確保、解放、メモリ確保/解放時にエラーが発生した際のデフォルトのリスナです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener& l) = delete; + DefaultMemoryListener& operator=(const DefaultMemoryListener& l) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyFree( const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + }; + + + /** + * メモリ管理。 + * メモリ確保、解放を行います。 + * ハンドラを登録することで、メモリ確保、解放、エラー発生時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* file; + extern thread_local int line; + extern thread_local const char* func; + + void setListener(MemoryListener& handler); + void entries(void (*handler)(const MemoryInfo& info)); + void freeif(bool (*handler)(const MemoryInfo& info)); + } + + +#if defined(SC_MEMORY_MANAGE) || defined(SCPP_MEMORY_MANAGE) + +#if (IS_SUPPORTED_CPP20) +// C++20 +#define NODISCARD [[nodiscard]] +#else +// C++20 以外 +#define NODISCARD +#endif + +// ----- C++11 ----- +NODISCARD void* operator new(std::size_t size); +NODISCARD void* operator new[](std::size_t size); +NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; +void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; +// 以下、実質メモリ管理しないため除外 +// NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; +// void operator delete(void* ptr, void*) noexcept; + +#if IS_SUPPORTED_CPP14 +// ----- C++14 ----- +void operator delete(void* ptr, std::size_t size) noexcept; +#endif + + +#if IS_SUPPORTED_CPP17 +// ----- C++17 ----- +// 現状未サポート [実装 +// NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +#endif // IS_SUPPORTED_CPP17 + +// ----- C++20 ----- +// C++11, C++17 の new に [[nodiscard]] が付与されている +// => マクロで対応済み + +// new の差し替え。 +// 先頭 +#define new \ + ((scpp::MemoryManager::file = __FILE__, \ + scpp::MemoryManager::line = __LINE__, \ + scpp::MemoryManager::func = __func__, \ + 0) && 0) ? 0 : new + +#endif // defined(SC_MEMORY_MANAGE) || defined(SCPP_MEMORY_MANAGE) + +} // namespace scpp + +#endif // SCPP_MEMORY_HPP diff --git a/modules/libscpp/include/scpp_unittest.hpp b/modules/libscpp/include/scpp_unittest.hpp new file mode 100644 index 0000000..038f7ab --- /dev/null +++ b/modules/libscpp/include/scpp_unittest.hpp @@ -0,0 +1,15 @@ +/** + * @file scpp_unittest.hpp + * @bried 簡易単体テスト用ヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_UNITTEST_HPP +#define SCPP_UNITTEST_HPP + + +#include + + +#endif // SCPP_UNITTEST_HPP + diff --git a/modules/libscpp/src/.scpp_exception.cpp.swp b/modules/libscpp/src/.scpp_exception.cpp.swp new file mode 100644 index 0000000..fa01bc2 --- /dev/null +++ b/modules/libscpp/src/.scpp_exception.cpp.swp Binary files differ diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/modules/libscpp/bkup/scpp_assert.hpp b/modules/libscpp/bkup/scpp_assert.hpp new file mode 100644 index 0000000..094836e --- /dev/null +++ b/modules/libscpp/bkup/scpp_assert.hpp @@ -0,0 +1,29 @@ +/** + * @file scpp_assert.hpp + * @bried Assert モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include + +namespace scpp +{ + + +class AssertError : public std::exception +{ + public: + AssertError() noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string% msg, +}; + + +} + + +#endif // SCPP_ASSERT_HPP diff --git a/modules/libscpp/bkup/scpp_exception.cpp b/modules/libscpp/bkup/scpp_exception.cpp new file mode 100644 index 0000000..5ed0c1c --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.cpp @@ -0,0 +1,13 @@ +/** + * @file scpp_exception.cpp + * @bried Exception モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + + +namespace scpp +{ +} + diff --git a/modules/libscpp/bkup/scpp_exception.hpp b/modules/libscpp/bkup/scpp_exception.hpp new file mode 100644 index 0000000..b37132f --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.hpp @@ -0,0 +1,65 @@ +/** + * @file scpp_exception.hpp + * @bried Exception モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + +/** + * 例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ +class Throwable: public std::exception +{ + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(const std::string& msg) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; +}; + + +/** + * 回復可能な例外クラス。 + */ +class Exception : public Throwable +{ + public: + Exception() noexcept; + Exception(const Throwable& t) noexcept; + Exception(const std::string& msg) noexcept; + virtual ~Exception() noexcept; +}; + + +/** + * 回復困難な例外クラス。 + */ +class Error : public Throwable +{ + public: + Error() noexcept; + Error(const Throwable& t) noexcept; + Error(const std::string& msg) noexcept; + virtual ~Error() noexcept; +}; + + +} + + +#endif // SCPP_EXCEPTION_HPP diff --git a/modules/libscpp/bkup/scpp_memory.cpp b/modules/libscpp/bkup/scpp_memory.cpp new file mode 100644 index 0000000..7213a9d --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.cpp @@ -0,0 +1,693 @@ +/** + * @file scpp_memory.cpp + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include +#include +#include +#include + + +// 本来の malloc, free を利用するため、ENABLED_MEMORY_MANAGE を無効にする +#ifdef ENABLED_MEMORY_MANAGE +#undef ENABLED_MEMORY_MANAGE +#endif +#include + + + +using namespace scpp; +namespace +{ + int const PADDING = sizeof(int) * 2; + int const MARK_ALLOCATED = 0x12340000; + int const MARK_ALLOCATED_NEW = 0x12341111; + int const MARK_ALLOCATED_NEW_ARRAY = 0x12342222; + int const MARK_DELETED = 0xFEDCBA00; + + bool infoIsInitialized = false; + std::mutex memMtx; //< 管理メモリ操作用 Mutex + MemoryInfo infoHead; //< 管理メモリ先頭 + MemoryInfo infoTail; //< 管理メモリ末尾 + MemoryInfo infoError; //< エラー発生時用 + MemoryListener* listener = 0; //< 通知リスナ + + // プロトタイプ宣言 + void init(); + void add(MemoryInfo* entry); + void remove(MemoryInfo* entry); + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func); + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng); + + /** + * new ハンドラを取得します。 + * + * @return new ハンドラ + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + /** + * メモリ管理初期化. + */ + void init() + { + if (!infoIsInitialized) + { + infoIsInitialized = true; + infoHead.fileName = infoTail.fileName = 0; + infoHead.lineNumber = infoTail.lineNumber = 0; + infoHead.functionName = infoTail.functionName = 0; + infoHead.size = infoTail.size = 0; + infoHead._prev = infoHead._next = &infoTail; + infoTail._prev = infoTail._next = &infoHead; + infoHead._mark = infoTail._mark = MARK_DELETED; + + // エラー処理用 + infoError.fileName = 0; + infoError.lineNumber = 0; + infoError.functionName = 0; + infoError.size = 0; + infoError._prev = 0; + infoError._next = 0; + infoError._mark = MARK_DELETED; + } + } + + + /** + * メモリエントリを追加します. + * + * @param entry 追加するエントリ + */ + void add(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + init(); + entry->_next = &infoTail; + entry->_prev = infoTail._prev; + infoTail._prev->_next = entry; + infoTail._prev = entry; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyAlloc(*entry); + } + } + + + /** + * メモリエントリを削除します. + * + * @param entry 削除するエントリ + */ + void remove(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyFree(*entry); + } + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func) + { + MemoryInfo* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast (::malloc(n + sizeof(MemoryInfo) + PADDING)); + if (entry != 0) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { + return 0; + } + } + + void* ptr = (entry + 1); + + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = ptr; + + // エントリに追加 + add(entry); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng) + { + if (isMng) + { // 管理メモリの場合, いったん削除 + remove(static_cast(ptr)); + } + + MemoryInfo* entry = static_cast (::realloc(ptr, n + sizeof(MemoryInfo) + PADDING)); + if (entry == 0) + { + // メモリ確保失敗 -> 元の領域は開放されないので再管理する + add(static_cast(ptr)); + errno = ENOMEM; + if (listener) + { // エラーハンドラが登録されている + infoError.size = n; + infoError.fileName = file; + infoError.lineNumber = line; + infoError.functionName = func; + listener->notifyError(infoError, "can't realloc"); + } + return 0; + } + + if (!isMng) + { // 管理対象外メモリの場合 + // |<---- 新たな確保領域 ---->| + // +----------+---------------+ + // |元々の領域|追加分+管理領域| + // +----------+---------------+ + // ↓ + // +--------+----------+------+ + // |管理領域|元々の領域|追加分| + // +--------+----------+------+ + memmove((entry + 1), entry, n); + } + + // 管理領域に情報を書き込む + void* nptr = (entry + 1); + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = nptr; + + // エントリに追加 + add(entry); + return nptr; + } + +} // namespace 無名 + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 以下, new / delete のオーバライド +// + + +void* operator new(std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new[](std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + +void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + + +void operator delete(void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } +} + +void operator delete(void* p, std::size_t) noexcept +{ + operator delete(p); +} + +void operator delete(void* p, const std::nothrow_t&) noexcept +{ + operator delete(p); +} + +void operator delete[](void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + +} + +void operator delete[](void* p, std::size_t) noexcept +{ + operator delete[](p); +} + +void operator delete[](void* p, const std::nothrow_t&) noexcept +{ + operator delete[](p); +} + + +namespace scpp +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// デフォルトのメモリ確保/開放時に実行されるリスナ +// + +DefaultMemoryListener::DefaultMemoryListener() +{ + // NOP +} +DefaultMemoryListener::~DefaultMemoryListener() +{ + // NOP +} + +/** + * メモリが確保された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyAlloc(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリが開放された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyFree(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリの確保/開放でエラーが発生した際に実行されるリスナ. + * エラー内容をエラー出力します. + * + * @param info メモリ情報 + * @param msg メッセージ + */ +void DefaultMemoryListener::notifyError(const MemoryInfo& info, const std::string& msg) +{ + std::cerr << "MemoryError: " << msg << std::endl; + std::cerr << "\tat " << info.fileName << ":" << info.lineNumber << ":" << info.functionName + << " (size = " << info.size << ")" << std::endl; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理 +// + +/** + * メモリ管理. + * メモリの確保, 開放を行います. + * リスナを登録することで, メモリ確保, 開放, エラー発生時の通知を + * 受信することができます. + * + * 以下のようにメモリを管理しています. + * @code + * + * |<----管理メモリ------------->| + * +--------+--------------------+ + * |管理領域|ユーザ使用メモリ領域| + * +--------+--------------------+ + * ↑ユーザにはこの位置を返す + * + * c++ なので std::list 等を使っても良いが, + * list のメモリ確保でエラーがでると本末転倒なので, + * メモリ確保時に管理領域をまとめて確保&管理する. + * @endcode + * + */ +namespace MemoryManager +{ + + thread_local const char* fileName = ""; // 名前一時保存用 + thread_local int lineNumber = 0; // 行番号一時保存用 + thread_local const char* functionName = ""; // 関数名一時保存用 + + /** + * メモリの確保,開放,エラー発生の通知を受信するリスナを登録します. + * + * @param l リスナ + */ + void setListener(MemoryListener* l) + { + listener = l; + } + + + /** + * 管理している全メモリエントリを引数に指定されたハンドラを実行します. + * デフォルトで用意しているハンドラ printMemoryInfo を使用できます. + * + * @param handler ハンドラ + */ + void entries(void (*handler)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + handler(*info); + info = info->_next; + } + } + + + /** + * 指定されたメソッドが true を返す管理メモリをクリア(削除)します. + * 本メソッド実行時, 管理しているメモリの情報を引数に + * 指定された関数が実行されます. + * + * [注意事項] + * 本メソッドでメモリはクリアしますが, デストラクタは呼び出されないので注意 + * + * 使用例) + * @code + * bool isCleanup(const scpp::MemoryInfo& info) + * { // 管理しているメモリ全てクリアする + * return true; + * } + * scpp::MemoryManager::cleanup(&isCleanup); + * @endcode + * + * @param isCleanup クリアするか否かを返す関数ポインタ + */ + void cleanup(bool (*isCleanup)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + bool ret = isCleanup(*info); + if (ret) + { // クリア対象 + MemoryInfo* tmpInfo; + tmpInfo = info; + info = info->_next; + remove(tmpInfo); + tmpInfo->size = 0; + tmpInfo->_mark = MARK_DELETED; + free(tmpInfo); + } + else + { + info = info->_next; + } + } + } + + + /** + * 指定されたメモリの情報を出力します. + * + * @param info メモリの情報 + */ + void printMemoryInfo(const MemoryInfo& info) + { + std::cout << "[MemoryInfo] " + << info.fileName << ":" + << info.lineNumber << ":" + << info.functionName << " (size = " + << info.size << ")" + << std::endl; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル名 + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, int line, const char* func) + { + void* ptr = allocate(size, MARK_ALLOCATED, file, line, func); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param nmemb 確保するメモリの要素数 + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func) + { + std::size_t n = nmemb * size; + void* ptr = allocate(n, MARK_ALLOCATED, file, line, func); + if (ptr) + { // callc なのでゼロクリアする + memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * ポインタが示すメモリブロックのサイズを変更します. + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func) + { + if (ptr == 0) + { // ptr が null の場合, malloc と等価 + ptr = malloc(size, file, line, func); + return ptr; + } + + if (size == 0) + { // size が 0 の場合, free と等価 + free(ptr); + return 0; + } + + // メモリ管理領域を取得 + MemoryInfo* entry = static_cast (ptr); + entry--; + void* nptr = 0; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 管理メモリ + nptr = reallocate(entry, size, MARK_ALLOCATED, file, line, func, true); + break; + case MARK_DELETED: // 削除済みメモリ + nptr = malloc(size, file, line, func); + break; + case MARK_ALLOCATED_NEW: // new で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new : can't realloc"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new[] : can't realloc"); } + break; + default: // 管理対象外メモリ + nptr = reallocate(ptr, size, MARK_ALLOCATED, file, line, func, false); + } + + return nptr; + } + + + /** + * 指定されたメモリを開放します. + * + * @param ptr 開放するメモリへのポインタ + */ + void free(void* ptr) + { + MemoryInfo* entry; + if (ptr == 0) + { // null ポインタの場合なにもしない + return; + } + + // メモリ管理領域を取得 + entry = (MemoryInfo*) ptr; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 確保されたメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + + } + + +} // namespace MemoryManager +} // namespace scpp + diff --git a/modules/libscpp/bkup/scpp_memory.hpp b/modules/libscpp/bkup/scpp_memory.hpp new file mode 100644 index 0000000..675ab75 --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.hpp @@ -0,0 +1,129 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * メモリの確保/解放/エラー発生時に呼び出されるリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHandler メソッドにて登録することで、 + * メモリの確保/解放/エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager で管理しているメモリに対してのみ有効です。 + * (MemoryManager::malloc, MemoryManager::calloc, MemoryManager::realloc) + * + * new, malloc, calloc などを対象とする場合、 + * ENABLED_MEMORY_MANAGE を定義してください。 + */ + class MemoryListener + { + public: + virtual void notifyAlloc(const MemoryInfo& info) = 0; + virtual void notifyFree(const MemoryInfo& info) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + virtual ~MemoryListener() = 0; + }; + + + /** + * メモリ確保/解放/エラー発生時のデフォルト通知インタフェースです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener&) = delete; + void operator=(const DefaultMemoryListener&) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info); + virtual void notifyFree(const MemoryInfo& info); + virtual void notifyError(const MemoryInfo& info, const std::string& msg); + }; + + + /** + * メモリ管理。 + * メモリの確保、解放を行います。 + * ハンドラを登録することで、メモリの確保/解放/エラー時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* fileName; + extern thread_local int lineNumber; + extern thread_local const char* functionName; + + void setListener(MemoryListener* handler); + void entries(void (*handler)(const MemoryInfo& info)); + void cleanup(bool (*isCleanup)(const MemoryInfo& info)); + void printMemoryInfo(const MemoryInfo& info); + void* malloc( std::size_t size, const char* file, int line, const char* func); + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func); + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func); + void free(void* ptr); + } + +} + + +#if (ENABLED_MEMORY_MANAGE) +#if IS_SUPPORTED_CPP20 +#define SCPP_NODISCARD [[nodiscard]] +#else +#define SCPP_NODISCARD +#endif + +SCPP_NODISCARD void* operator new(std::size_t size); +SCPP_NODISCARD void* operator new[](std::size_t size); + +SCPP_NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +SCPP_NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; + +// void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; + +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; + +// 実質メモリ管理しないので除外 +// SCPP_NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; + +#if IS_SUPPORTED_CPP17 +// 以下、未サポート +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// +#endif + +#define new \ + ((scpp::MemoryManager::fileName = __FILE__, \ + scpp::MemoryManager::lineNumber = __LINE__, \ + scpp::MemoryManager::functionName = __func__, \ + 0) && 0) ? 0 : new + +#define malloc(size) scpp::MemoryManager::malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) scpp::MemoryManager::calloc(nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) scpp::MemoryManager::realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) scpp::MemoryManager::free(ptr) + +#endif // (ENABLED_MEMORY_MANAGE) + +#endif // SCPP_MEMORY_HPP diff --git a/modules/libscpp/bkup/scpp_unittest.hpp b/modules/libscpp/bkup/scpp_unittest.hpp new file mode 100644 index 0000000..9b2b154 --- /dev/null +++ b/modules/libscpp/bkup/scpp_unittest.hpp @@ -0,0 +1,11 @@ +/** + * @file scpp_unitteset.hpp + * @bried 単体テストモジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_UNITTEST_HPP +#define SCPP_UNITTEST_HPP + + +#endif // SCPP_UNITTEST_HPP diff --git a/modules/libscpp/include/scpp.hpp b/modules/libscpp/include/scpp.hpp new file mode 100644 index 0000000..00aaa98 --- /dev/null +++ b/modules/libscpp/include/scpp.hpp @@ -0,0 +1,15 @@ +/** + * @file scpp.hpp + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include +#include +#include + +#endif // SCPP_H + diff --git a/modules/libscpp/include/scpp_assert.hpp b/modules/libscpp/include/scpp_assert.hpp new file mode 100644 index 0000000..76aeb30 --- /dev/null +++ b/modules/libscpp/include/scpp_assert.hpp @@ -0,0 +1,24 @@ +/** + * @file scpp_assert.hpp + * @bried アサーションモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * アサーション関数が失敗するとき、エラーメッセージを出力します。 + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include +#include + +namespace scpp +{ + +/** + * アサーションに失敗した際に throw される Erro です。 + */ + + +#endif // SCPP_ASSERT_HPP + diff --git a/modules/libscpp/include/scpp_compiler.hpp b/modules/libscpp/include/scpp_compiler.hpp new file mode 100644 index 0000000..c56a6e2 --- /dev/null +++ b/modules/libscpp/include/scpp_compiler.hpp @@ -0,0 +1,42 @@ +/** + * @file scpp_compiler.hpp + * @bried C++言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C++言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + */ +#ifndef SCPP_COMPILER_H +#define SCPP_COMPILER_H +#ifdef __cplusplus + + +#if (__cplusplus >= 201103L) +/* ----- C++11 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (__cplusplus >= 202002L) +#define IS_SUPPORTED_CPP17 (__cplusplus >= 201703L) +#define IS_SUPPORTED_CPP14 (__cplusplus >= 201402L) +#define IS_SUPPORTED_CPP11 (__cplusplus >= 201103L) +#define IS_SUPPORTED_C17 (0) +#define IS_SUPPORTED_C11 (0) +#define IS_SUPPORTED_C99 (0) + +#else +/* ----- C++11 以前の場合はエラーとする */ +#error "unsupported c++ version, please use c++11 or later" + +#endif /* (__cplusplus >= 201103L) */ + + +#endif /* __cplusplus */ +#endif /* SCPP_COMPILER_H */ diff --git a/modules/libscpp/include/scpp_exception.hpp b/modules/libscpp/include/scpp_exception.hpp new file mode 100644 index 0000000..70df85f --- /dev/null +++ b/modules/libscpp/include/scpp_exception.hpp @@ -0,0 +1,77 @@ +/** + * @file scpp_exception.hpp + * @bried 例外クラス用ヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * 本ライブラリの例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ + class Throwable : public std::exception + { + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(Throwable&& t) noexcept; + Throwable(const std::string& msg) noexcept; + Throwable& operator=(const Throwable& t) noexcept; + Throwable& operator=(Throwable&& t) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; + }; + + + /** + * 本ライブラリの Exception クラス。 + * 本ライブラリにて発生したエラーのうち、回復可能なエラーは、 + * 本クラスを継承した Exception クラスを throw します。 + */ + class Exception : public Throwable + { + public: + Exception() noexcept; + Exception(const Exception& e) noexcept; + Exception(Exception&& e) noexcept; + Exception(const std::string& msg) noexcept; + Exception& operator=(const Exception& t) noexcept; + Exception& operator=(Exception&& t) noexcept; + virtual ~Exception() noexcept; + }; + + + /** + * 本ライブラリの Error クラス。 + * 本ライブラリにて発生したエラーのうち、回復困難なエラーは、 + * 本クラスを継承した Error クラスを throw します。 + */ + class Error : public Throwable + { + public: + Error() noexcept; + Error(const Error& t) noexcept; + Error(Error&& t) noexcept; + Error(const std::string& msg) noexcept; + Error& operator=(const Error& t) noexcept; + Error& operator=(Error&& t) noexcept; + virtual ~Error() noexcept; + }; + +} // namespace scpp + +#endif // SCPP_EXCEPTION_HPP + diff --git a/modules/libscpp/include/scpp_memory.hpp b/modules/libscpp/include/scpp_memory.hpp new file mode 100644 index 0000000..7a23506 --- /dev/null +++ b/modules/libscpp/include/scpp_memory.hpp @@ -0,0 +1,135 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include +#include + + +#include + +namespace scpp +{ + +#include + + typedef sc_memory MemoryInfo; + + + /** + * メモリが確保、解放、あるいはメモリ確保/解放時にエラーが発生した際のリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHander メソッドにて登録することで、 + * メモリの確保、解放、エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager にて管理しているメモリに対してのみ有効です。 + */ + class MemoryListener + { + public: + MemoryListener(); + MemoryListener(const MemoryListener& l) = delete; + MemoryListener& operator=(const MemoryListener& l) = delete; + virtual ~MemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyFree( const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + }; + + + /** + * メモリ確保、解放、メモリ確保/解放時にエラーが発生した際のデフォルトのリスナです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener& l) = delete; + DefaultMemoryListener& operator=(const DefaultMemoryListener& l) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyFree( const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + }; + + + /** + * メモリ管理。 + * メモリ確保、解放を行います。 + * ハンドラを登録することで、メモリ確保、解放、エラー発生時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* file; + extern thread_local int line; + extern thread_local const char* func; + + void setListener(MemoryListener& handler); + void entries(void (*handler)(const MemoryInfo& info)); + void freeif(bool (*handler)(const MemoryInfo& info)); + } + + +#if defined(SC_MEMORY_MANAGE) || defined(SCPP_MEMORY_MANAGE) + +#if (IS_SUPPORTED_CPP20) +// C++20 +#define NODISCARD [[nodiscard]] +#else +// C++20 以外 +#define NODISCARD +#endif + +// ----- C++11 ----- +NODISCARD void* operator new(std::size_t size); +NODISCARD void* operator new[](std::size_t size); +NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; +void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; +// 以下、実質メモリ管理しないため除外 +// NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; +// void operator delete(void* ptr, void*) noexcept; + +#if IS_SUPPORTED_CPP14 +// ----- C++14 ----- +void operator delete(void* ptr, std::size_t size) noexcept; +#endif + + +#if IS_SUPPORTED_CPP17 +// ----- C++17 ----- +// 現状未サポート [実装 +// NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +#endif // IS_SUPPORTED_CPP17 + +// ----- C++20 ----- +// C++11, C++17 の new に [[nodiscard]] が付与されている +// => マクロで対応済み + +// new の差し替え。 +// 先頭 +#define new \ + ((scpp::MemoryManager::file = __FILE__, \ + scpp::MemoryManager::line = __LINE__, \ + scpp::MemoryManager::func = __func__, \ + 0) && 0) ? 0 : new + +#endif // defined(SC_MEMORY_MANAGE) || defined(SCPP_MEMORY_MANAGE) + +} // namespace scpp + +#endif // SCPP_MEMORY_HPP diff --git a/modules/libscpp/include/scpp_unittest.hpp b/modules/libscpp/include/scpp_unittest.hpp new file mode 100644 index 0000000..038f7ab --- /dev/null +++ b/modules/libscpp/include/scpp_unittest.hpp @@ -0,0 +1,15 @@ +/** + * @file scpp_unittest.hpp + * @bried 簡易単体テスト用ヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_UNITTEST_HPP +#define SCPP_UNITTEST_HPP + + +#include + + +#endif // SCPP_UNITTEST_HPP + diff --git a/modules/libscpp/src/.scpp_exception.cpp.swp b/modules/libscpp/src/.scpp_exception.cpp.swp new file mode 100644 index 0000000..fa01bc2 --- /dev/null +++ b/modules/libscpp/src/.scpp_exception.cpp.swp Binary files differ diff --git a/modules/libscpp/src/scpp_exception.cpp b/modules/libscpp/src/scpp_exception.cpp new file mode 100644 index 0000000..862f834 --- /dev/null +++ b/modules/libscpp/src/scpp_exception.cpp @@ -0,0 +1,272 @@ +/** + * @file scpp_exception.cpp + * @bried Java ライクな Exception を扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + +#include +#include + +#include + + +namespace scpp +{ + + //////////////////////////////////////////////////////////////////////////// + // + // Throwable + // + + /** + * 最後に発生した errno に対応するメッセージを持つ Throwable を構築します。 + * エラーメッセージを取得できない場合、空文字がエラーメッセージに設定されます。 + */ + Throwable::Throwable() noexcept : message(sc_get_errmsg(NULL, 0, sc_get_errno())) + { + // NOP + } + + + /** + * コピーコンストラクタ。 + * + * @param t コピー元 + */ + Throwable::Throwable(const Throwable& t) noexcept : message(t.message) + { + // NOP + } + + + /** + * ムーブコンストラクタ。 + * + * @param t ムーブ元 + */ + Throwable::Throwable(Throwable&& t) noexcept : message(std::move(t.message)) + { + // NOP + } + + + /** + * 指定されたメッセージを持つ Throwable を構築します。 + * + * @param msg メッセージ + */ + Throwable::Throwable(const std::string& msg) noexcept : message(msg) + { + // NOP + } + + + /** + * コピー代入演算子 + * + * @param t 代入元 + */ + Throwable& Throwable::operator=(const Throwable& t) noexcept + { + this->message = t.message; + return (*this); + } + + + /** + * ムーブ代入演算子 + * + * @param t 代入元 + */ + Throwable& Throwable::operator=(Throwable&& t) noexcept + { + this->message = std::move(t.message); + return (*this); + } + + + /** + * デストラクタ。 + */ + Throwable::~Throwable() noexcept + { + // NOP + } + + + /** + * エラーメッセージを返します。 + * + * @return エラーメッセージ + */ + const char* Throwable::what() const noexcept + { + return message.c_str(); + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // Exception + // + + /** + * Exception を構築します。 + */ + Exception::Exception() noexcept : Throwable() + { + // NOP + } + + + /** + * コピーコンストラクタ。 + * + * @param t コピー元 + */ + Exception::Exception(const Exception& t) noexcept : Throwable(t) + { + // NOP + } + + + /** + * ムーブコンストラクタ。 + * + * @param t ムーブ元 + */ + Exception::Exception(Exception&& t) noexcept : Throwable(t) + { + // NOP + } + + + /** + * 指定されたメッセージを持つ Exception を構築します。 + * + * @param msg メッセージ + */ + Exception::Exception(const std::string& msg) noexcept : Throwable(msg) + { + // NOP + } + + + /** + * コピー代入演算子 + * + * @param t 代入元 + */ + Exception& Exception::operator=(const Exception& t) noexcept + { + Throwable::operator=(t); + return (*this); + } + + + /** + * ムーブ代入演算子 + * + * @param t 代入元 + */ + Exception& Exception::operator=(Exception&& t) noexcept + { + Throwable::operator=(t); + return (*this); + } + + + /** + * デストラクタ。 + */ + Exception::~Exception() noexcept + { + // NOP + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // Error + // + + /** + * Error を構築します。 + */ + Error::Error() noexcept : Throwable() + { + // NOP + } + + + /** + * コピーコンストラクタ。 + * + * @param t コピー元 + */ + Error::Error(const Error& t) noexcept : Throwable(t) + { + // NOP + } + + + /** + * ムーブコンストラクタ。 + * + * @param t ムーブ元 + */ + Error::Error(Error&& t) noexcept : Throwable(t) + { + // NOP + } + + + /** + * 指定されたメッセージを持つ Error を構築します。 + * + * @param msg メッセージ + */ + Error::Error(const std::string& msg) noexcept : Throwable(msg) + { + // NOP + } + + + /** + * コピー代入演算子 + * + * @param t 代入元 + */ + Error& Error::operator=(const Error& t) noexcept + { + Throwable::operator=(t); + return (*this); + } + + + /** + * ムーブ代入演算子 + * + * @param t 代入元 + */ + Error& Error::operator=(Error&& t) noexcept + { + Throwable::operator=(t); + return (*this); + } + + + /** + * デストラクタ。 + */ + Error::~Error() noexcept + { + // NOP + } + +} + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/modules/libscpp/bkup/scpp_assert.hpp b/modules/libscpp/bkup/scpp_assert.hpp new file mode 100644 index 0000000..094836e --- /dev/null +++ b/modules/libscpp/bkup/scpp_assert.hpp @@ -0,0 +1,29 @@ +/** + * @file scpp_assert.hpp + * @bried Assert モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include + +namespace scpp +{ + + +class AssertError : public std::exception +{ + public: + AssertError() noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string% msg, +}; + + +} + + +#endif // SCPP_ASSERT_HPP diff --git a/modules/libscpp/bkup/scpp_exception.cpp b/modules/libscpp/bkup/scpp_exception.cpp new file mode 100644 index 0000000..5ed0c1c --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.cpp @@ -0,0 +1,13 @@ +/** + * @file scpp_exception.cpp + * @bried Exception モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + + +namespace scpp +{ +} + diff --git a/modules/libscpp/bkup/scpp_exception.hpp b/modules/libscpp/bkup/scpp_exception.hpp new file mode 100644 index 0000000..b37132f --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.hpp @@ -0,0 +1,65 @@ +/** + * @file scpp_exception.hpp + * @bried Exception モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + +/** + * 例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ +class Throwable: public std::exception +{ + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(const std::string& msg) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; +}; + + +/** + * 回復可能な例外クラス。 + */ +class Exception : public Throwable +{ + public: + Exception() noexcept; + Exception(const Throwable& t) noexcept; + Exception(const std::string& msg) noexcept; + virtual ~Exception() noexcept; +}; + + +/** + * 回復困難な例外クラス。 + */ +class Error : public Throwable +{ + public: + Error() noexcept; + Error(const Throwable& t) noexcept; + Error(const std::string& msg) noexcept; + virtual ~Error() noexcept; +}; + + +} + + +#endif // SCPP_EXCEPTION_HPP diff --git a/modules/libscpp/bkup/scpp_memory.cpp b/modules/libscpp/bkup/scpp_memory.cpp new file mode 100644 index 0000000..7213a9d --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.cpp @@ -0,0 +1,693 @@ +/** + * @file scpp_memory.cpp + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include +#include +#include +#include + + +// 本来の malloc, free を利用するため、ENABLED_MEMORY_MANAGE を無効にする +#ifdef ENABLED_MEMORY_MANAGE +#undef ENABLED_MEMORY_MANAGE +#endif +#include + + + +using namespace scpp; +namespace +{ + int const PADDING = sizeof(int) * 2; + int const MARK_ALLOCATED = 0x12340000; + int const MARK_ALLOCATED_NEW = 0x12341111; + int const MARK_ALLOCATED_NEW_ARRAY = 0x12342222; + int const MARK_DELETED = 0xFEDCBA00; + + bool infoIsInitialized = false; + std::mutex memMtx; //< 管理メモリ操作用 Mutex + MemoryInfo infoHead; //< 管理メモリ先頭 + MemoryInfo infoTail; //< 管理メモリ末尾 + MemoryInfo infoError; //< エラー発生時用 + MemoryListener* listener = 0; //< 通知リスナ + + // プロトタイプ宣言 + void init(); + void add(MemoryInfo* entry); + void remove(MemoryInfo* entry); + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func); + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng); + + /** + * new ハンドラを取得します。 + * + * @return new ハンドラ + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + /** + * メモリ管理初期化. + */ + void init() + { + if (!infoIsInitialized) + { + infoIsInitialized = true; + infoHead.fileName = infoTail.fileName = 0; + infoHead.lineNumber = infoTail.lineNumber = 0; + infoHead.functionName = infoTail.functionName = 0; + infoHead.size = infoTail.size = 0; + infoHead._prev = infoHead._next = &infoTail; + infoTail._prev = infoTail._next = &infoHead; + infoHead._mark = infoTail._mark = MARK_DELETED; + + // エラー処理用 + infoError.fileName = 0; + infoError.lineNumber = 0; + infoError.functionName = 0; + infoError.size = 0; + infoError._prev = 0; + infoError._next = 0; + infoError._mark = MARK_DELETED; + } + } + + + /** + * メモリエントリを追加します. + * + * @param entry 追加するエントリ + */ + void add(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + init(); + entry->_next = &infoTail; + entry->_prev = infoTail._prev; + infoTail._prev->_next = entry; + infoTail._prev = entry; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyAlloc(*entry); + } + } + + + /** + * メモリエントリを削除します. + * + * @param entry 削除するエントリ + */ + void remove(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyFree(*entry); + } + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func) + { + MemoryInfo* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast (::malloc(n + sizeof(MemoryInfo) + PADDING)); + if (entry != 0) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { + return 0; + } + } + + void* ptr = (entry + 1); + + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = ptr; + + // エントリに追加 + add(entry); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng) + { + if (isMng) + { // 管理メモリの場合, いったん削除 + remove(static_cast(ptr)); + } + + MemoryInfo* entry = static_cast (::realloc(ptr, n + sizeof(MemoryInfo) + PADDING)); + if (entry == 0) + { + // メモリ確保失敗 -> 元の領域は開放されないので再管理する + add(static_cast(ptr)); + errno = ENOMEM; + if (listener) + { // エラーハンドラが登録されている + infoError.size = n; + infoError.fileName = file; + infoError.lineNumber = line; + infoError.functionName = func; + listener->notifyError(infoError, "can't realloc"); + } + return 0; + } + + if (!isMng) + { // 管理対象外メモリの場合 + // |<---- 新たな確保領域 ---->| + // +----------+---------------+ + // |元々の領域|追加分+管理領域| + // +----------+---------------+ + // ↓ + // +--------+----------+------+ + // |管理領域|元々の領域|追加分| + // +--------+----------+------+ + memmove((entry + 1), entry, n); + } + + // 管理領域に情報を書き込む + void* nptr = (entry + 1); + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = nptr; + + // エントリに追加 + add(entry); + return nptr; + } + +} // namespace 無名 + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 以下, new / delete のオーバライド +// + + +void* operator new(std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new[](std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + +void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + + +void operator delete(void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } +} + +void operator delete(void* p, std::size_t) noexcept +{ + operator delete(p); +} + +void operator delete(void* p, const std::nothrow_t&) noexcept +{ + operator delete(p); +} + +void operator delete[](void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + +} + +void operator delete[](void* p, std::size_t) noexcept +{ + operator delete[](p); +} + +void operator delete[](void* p, const std::nothrow_t&) noexcept +{ + operator delete[](p); +} + + +namespace scpp +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// デフォルトのメモリ確保/開放時に実行されるリスナ +// + +DefaultMemoryListener::DefaultMemoryListener() +{ + // NOP +} +DefaultMemoryListener::~DefaultMemoryListener() +{ + // NOP +} + +/** + * メモリが確保された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyAlloc(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリが開放された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyFree(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリの確保/開放でエラーが発生した際に実行されるリスナ. + * エラー内容をエラー出力します. + * + * @param info メモリ情報 + * @param msg メッセージ + */ +void DefaultMemoryListener::notifyError(const MemoryInfo& info, const std::string& msg) +{ + std::cerr << "MemoryError: " << msg << std::endl; + std::cerr << "\tat " << info.fileName << ":" << info.lineNumber << ":" << info.functionName + << " (size = " << info.size << ")" << std::endl; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理 +// + +/** + * メモリ管理. + * メモリの確保, 開放を行います. + * リスナを登録することで, メモリ確保, 開放, エラー発生時の通知を + * 受信することができます. + * + * 以下のようにメモリを管理しています. + * @code + * + * |<----管理メモリ------------->| + * +--------+--------------------+ + * |管理領域|ユーザ使用メモリ領域| + * +--------+--------------------+ + * ↑ユーザにはこの位置を返す + * + * c++ なので std::list 等を使っても良いが, + * list のメモリ確保でエラーがでると本末転倒なので, + * メモリ確保時に管理領域をまとめて確保&管理する. + * @endcode + * + */ +namespace MemoryManager +{ + + thread_local const char* fileName = ""; // 名前一時保存用 + thread_local int lineNumber = 0; // 行番号一時保存用 + thread_local const char* functionName = ""; // 関数名一時保存用 + + /** + * メモリの確保,開放,エラー発生の通知を受信するリスナを登録します. + * + * @param l リスナ + */ + void setListener(MemoryListener* l) + { + listener = l; + } + + + /** + * 管理している全メモリエントリを引数に指定されたハンドラを実行します. + * デフォルトで用意しているハンドラ printMemoryInfo を使用できます. + * + * @param handler ハンドラ + */ + void entries(void (*handler)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + handler(*info); + info = info->_next; + } + } + + + /** + * 指定されたメソッドが true を返す管理メモリをクリア(削除)します. + * 本メソッド実行時, 管理しているメモリの情報を引数に + * 指定された関数が実行されます. + * + * [注意事項] + * 本メソッドでメモリはクリアしますが, デストラクタは呼び出されないので注意 + * + * 使用例) + * @code + * bool isCleanup(const scpp::MemoryInfo& info) + * { // 管理しているメモリ全てクリアする + * return true; + * } + * scpp::MemoryManager::cleanup(&isCleanup); + * @endcode + * + * @param isCleanup クリアするか否かを返す関数ポインタ + */ + void cleanup(bool (*isCleanup)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + bool ret = isCleanup(*info); + if (ret) + { // クリア対象 + MemoryInfo* tmpInfo; + tmpInfo = info; + info = info->_next; + remove(tmpInfo); + tmpInfo->size = 0; + tmpInfo->_mark = MARK_DELETED; + free(tmpInfo); + } + else + { + info = info->_next; + } + } + } + + + /** + * 指定されたメモリの情報を出力します. + * + * @param info メモリの情報 + */ + void printMemoryInfo(const MemoryInfo& info) + { + std::cout << "[MemoryInfo] " + << info.fileName << ":" + << info.lineNumber << ":" + << info.functionName << " (size = " + << info.size << ")" + << std::endl; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル名 + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, int line, const char* func) + { + void* ptr = allocate(size, MARK_ALLOCATED, file, line, func); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param nmemb 確保するメモリの要素数 + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func) + { + std::size_t n = nmemb * size; + void* ptr = allocate(n, MARK_ALLOCATED, file, line, func); + if (ptr) + { // callc なのでゼロクリアする + memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * ポインタが示すメモリブロックのサイズを変更します. + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func) + { + if (ptr == 0) + { // ptr が null の場合, malloc と等価 + ptr = malloc(size, file, line, func); + return ptr; + } + + if (size == 0) + { // size が 0 の場合, free と等価 + free(ptr); + return 0; + } + + // メモリ管理領域を取得 + MemoryInfo* entry = static_cast (ptr); + entry--; + void* nptr = 0; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 管理メモリ + nptr = reallocate(entry, size, MARK_ALLOCATED, file, line, func, true); + break; + case MARK_DELETED: // 削除済みメモリ + nptr = malloc(size, file, line, func); + break; + case MARK_ALLOCATED_NEW: // new で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new : can't realloc"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new[] : can't realloc"); } + break; + default: // 管理対象外メモリ + nptr = reallocate(ptr, size, MARK_ALLOCATED, file, line, func, false); + } + + return nptr; + } + + + /** + * 指定されたメモリを開放します. + * + * @param ptr 開放するメモリへのポインタ + */ + void free(void* ptr) + { + MemoryInfo* entry; + if (ptr == 0) + { // null ポインタの場合なにもしない + return; + } + + // メモリ管理領域を取得 + entry = (MemoryInfo*) ptr; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 確保されたメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + + } + + +} // namespace MemoryManager +} // namespace scpp + diff --git a/modules/libscpp/bkup/scpp_memory.hpp b/modules/libscpp/bkup/scpp_memory.hpp new file mode 100644 index 0000000..675ab75 --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.hpp @@ -0,0 +1,129 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * メモリの確保/解放/エラー発生時に呼び出されるリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHandler メソッドにて登録することで、 + * メモリの確保/解放/エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager で管理しているメモリに対してのみ有効です。 + * (MemoryManager::malloc, MemoryManager::calloc, MemoryManager::realloc) + * + * new, malloc, calloc などを対象とする場合、 + * ENABLED_MEMORY_MANAGE を定義してください。 + */ + class MemoryListener + { + public: + virtual void notifyAlloc(const MemoryInfo& info) = 0; + virtual void notifyFree(const MemoryInfo& info) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + virtual ~MemoryListener() = 0; + }; + + + /** + * メモリ確保/解放/エラー発生時のデフォルト通知インタフェースです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener&) = delete; + void operator=(const DefaultMemoryListener&) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info); + virtual void notifyFree(const MemoryInfo& info); + virtual void notifyError(const MemoryInfo& info, const std::string& msg); + }; + + + /** + * メモリ管理。 + * メモリの確保、解放を行います。 + * ハンドラを登録することで、メモリの確保/解放/エラー時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* fileName; + extern thread_local int lineNumber; + extern thread_local const char* functionName; + + void setListener(MemoryListener* handler); + void entries(void (*handler)(const MemoryInfo& info)); + void cleanup(bool (*isCleanup)(const MemoryInfo& info)); + void printMemoryInfo(const MemoryInfo& info); + void* malloc( std::size_t size, const char* file, int line, const char* func); + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func); + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func); + void free(void* ptr); + } + +} + + +#if (ENABLED_MEMORY_MANAGE) +#if IS_SUPPORTED_CPP20 +#define SCPP_NODISCARD [[nodiscard]] +#else +#define SCPP_NODISCARD +#endif + +SCPP_NODISCARD void* operator new(std::size_t size); +SCPP_NODISCARD void* operator new[](std::size_t size); + +SCPP_NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +SCPP_NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; + +// void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; + +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; + +// 実質メモリ管理しないので除外 +// SCPP_NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; + +#if IS_SUPPORTED_CPP17 +// 以下、未サポート +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// +#endif + +#define new \ + ((scpp::MemoryManager::fileName = __FILE__, \ + scpp::MemoryManager::lineNumber = __LINE__, \ + scpp::MemoryManager::functionName = __func__, \ + 0) && 0) ? 0 : new + +#define malloc(size) scpp::MemoryManager::malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) scpp::MemoryManager::calloc(nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) scpp::MemoryManager::realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) scpp::MemoryManager::free(ptr) + +#endif // (ENABLED_MEMORY_MANAGE) + +#endif // SCPP_MEMORY_HPP diff --git a/modules/libscpp/bkup/scpp_unittest.hpp b/modules/libscpp/bkup/scpp_unittest.hpp new file mode 100644 index 0000000..9b2b154 --- /dev/null +++ b/modules/libscpp/bkup/scpp_unittest.hpp @@ -0,0 +1,11 @@ +/** + * @file scpp_unitteset.hpp + * @bried 単体テストモジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_UNITTEST_HPP +#define SCPP_UNITTEST_HPP + + +#endif // SCPP_UNITTEST_HPP diff --git a/modules/libscpp/include/scpp.hpp b/modules/libscpp/include/scpp.hpp new file mode 100644 index 0000000..00aaa98 --- /dev/null +++ b/modules/libscpp/include/scpp.hpp @@ -0,0 +1,15 @@ +/** + * @file scpp.hpp + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include +#include +#include + +#endif // SCPP_H + diff --git a/modules/libscpp/include/scpp_assert.hpp b/modules/libscpp/include/scpp_assert.hpp new file mode 100644 index 0000000..76aeb30 --- /dev/null +++ b/modules/libscpp/include/scpp_assert.hpp @@ -0,0 +1,24 @@ +/** + * @file scpp_assert.hpp + * @bried アサーションモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * アサーション関数が失敗するとき、エラーメッセージを出力します。 + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include +#include + +namespace scpp +{ + +/** + * アサーションに失敗した際に throw される Erro です。 + */ + + +#endif // SCPP_ASSERT_HPP + diff --git a/modules/libscpp/include/scpp_compiler.hpp b/modules/libscpp/include/scpp_compiler.hpp new file mode 100644 index 0000000..c56a6e2 --- /dev/null +++ b/modules/libscpp/include/scpp_compiler.hpp @@ -0,0 +1,42 @@ +/** + * @file scpp_compiler.hpp + * @bried C++言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C++言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + */ +#ifndef SCPP_COMPILER_H +#define SCPP_COMPILER_H +#ifdef __cplusplus + + +#if (__cplusplus >= 201103L) +/* ----- C++11 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (__cplusplus >= 202002L) +#define IS_SUPPORTED_CPP17 (__cplusplus >= 201703L) +#define IS_SUPPORTED_CPP14 (__cplusplus >= 201402L) +#define IS_SUPPORTED_CPP11 (__cplusplus >= 201103L) +#define IS_SUPPORTED_C17 (0) +#define IS_SUPPORTED_C11 (0) +#define IS_SUPPORTED_C99 (0) + +#else +/* ----- C++11 以前の場合はエラーとする */ +#error "unsupported c++ version, please use c++11 or later" + +#endif /* (__cplusplus >= 201103L) */ + + +#endif /* __cplusplus */ +#endif /* SCPP_COMPILER_H */ diff --git a/modules/libscpp/include/scpp_exception.hpp b/modules/libscpp/include/scpp_exception.hpp new file mode 100644 index 0000000..70df85f --- /dev/null +++ b/modules/libscpp/include/scpp_exception.hpp @@ -0,0 +1,77 @@ +/** + * @file scpp_exception.hpp + * @bried 例外クラス用ヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * 本ライブラリの例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ + class Throwable : public std::exception + { + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(Throwable&& t) noexcept; + Throwable(const std::string& msg) noexcept; + Throwable& operator=(const Throwable& t) noexcept; + Throwable& operator=(Throwable&& t) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; + }; + + + /** + * 本ライブラリの Exception クラス。 + * 本ライブラリにて発生したエラーのうち、回復可能なエラーは、 + * 本クラスを継承した Exception クラスを throw します。 + */ + class Exception : public Throwable + { + public: + Exception() noexcept; + Exception(const Exception& e) noexcept; + Exception(Exception&& e) noexcept; + Exception(const std::string& msg) noexcept; + Exception& operator=(const Exception& t) noexcept; + Exception& operator=(Exception&& t) noexcept; + virtual ~Exception() noexcept; + }; + + + /** + * 本ライブラリの Error クラス。 + * 本ライブラリにて発生したエラーのうち、回復困難なエラーは、 + * 本クラスを継承した Error クラスを throw します。 + */ + class Error : public Throwable + { + public: + Error() noexcept; + Error(const Error& t) noexcept; + Error(Error&& t) noexcept; + Error(const std::string& msg) noexcept; + Error& operator=(const Error& t) noexcept; + Error& operator=(Error&& t) noexcept; + virtual ~Error() noexcept; + }; + +} // namespace scpp + +#endif // SCPP_EXCEPTION_HPP + diff --git a/modules/libscpp/include/scpp_memory.hpp b/modules/libscpp/include/scpp_memory.hpp new file mode 100644 index 0000000..7a23506 --- /dev/null +++ b/modules/libscpp/include/scpp_memory.hpp @@ -0,0 +1,135 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include +#include + + +#include + +namespace scpp +{ + +#include + + typedef sc_memory MemoryInfo; + + + /** + * メモリが確保、解放、あるいはメモリ確保/解放時にエラーが発生した際のリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHander メソッドにて登録することで、 + * メモリの確保、解放、エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager にて管理しているメモリに対してのみ有効です。 + */ + class MemoryListener + { + public: + MemoryListener(); + MemoryListener(const MemoryListener& l) = delete; + MemoryListener& operator=(const MemoryListener& l) = delete; + virtual ~MemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyFree( const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + }; + + + /** + * メモリ確保、解放、メモリ確保/解放時にエラーが発生した際のデフォルトのリスナです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener& l) = delete; + DefaultMemoryListener& operator=(const DefaultMemoryListener& l) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyFree( const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + }; + + + /** + * メモリ管理。 + * メモリ確保、解放を行います。 + * ハンドラを登録することで、メモリ確保、解放、エラー発生時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* file; + extern thread_local int line; + extern thread_local const char* func; + + void setListener(MemoryListener& handler); + void entries(void (*handler)(const MemoryInfo& info)); + void freeif(bool (*handler)(const MemoryInfo& info)); + } + + +#if defined(SC_MEMORY_MANAGE) || defined(SCPP_MEMORY_MANAGE) + +#if (IS_SUPPORTED_CPP20) +// C++20 +#define NODISCARD [[nodiscard]] +#else +// C++20 以外 +#define NODISCARD +#endif + +// ----- C++11 ----- +NODISCARD void* operator new(std::size_t size); +NODISCARD void* operator new[](std::size_t size); +NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; +void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; +// 以下、実質メモリ管理しないため除外 +// NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; +// void operator delete(void* ptr, void*) noexcept; + +#if IS_SUPPORTED_CPP14 +// ----- C++14 ----- +void operator delete(void* ptr, std::size_t size) noexcept; +#endif + + +#if IS_SUPPORTED_CPP17 +// ----- C++17 ----- +// 現状未サポート [実装 +// NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +#endif // IS_SUPPORTED_CPP17 + +// ----- C++20 ----- +// C++11, C++17 の new に [[nodiscard]] が付与されている +// => マクロで対応済み + +// new の差し替え。 +// 先頭 +#define new \ + ((scpp::MemoryManager::file = __FILE__, \ + scpp::MemoryManager::line = __LINE__, \ + scpp::MemoryManager::func = __func__, \ + 0) && 0) ? 0 : new + +#endif // defined(SC_MEMORY_MANAGE) || defined(SCPP_MEMORY_MANAGE) + +} // namespace scpp + +#endif // SCPP_MEMORY_HPP diff --git a/modules/libscpp/include/scpp_unittest.hpp b/modules/libscpp/include/scpp_unittest.hpp new file mode 100644 index 0000000..038f7ab --- /dev/null +++ b/modules/libscpp/include/scpp_unittest.hpp @@ -0,0 +1,15 @@ +/** + * @file scpp_unittest.hpp + * @bried 簡易単体テスト用ヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_UNITTEST_HPP +#define SCPP_UNITTEST_HPP + + +#include + + +#endif // SCPP_UNITTEST_HPP + diff --git a/modules/libscpp/src/.scpp_exception.cpp.swp b/modules/libscpp/src/.scpp_exception.cpp.swp new file mode 100644 index 0000000..fa01bc2 --- /dev/null +++ b/modules/libscpp/src/.scpp_exception.cpp.swp Binary files differ diff --git a/modules/libscpp/src/scpp_exception.cpp b/modules/libscpp/src/scpp_exception.cpp new file mode 100644 index 0000000..862f834 --- /dev/null +++ b/modules/libscpp/src/scpp_exception.cpp @@ -0,0 +1,272 @@ +/** + * @file scpp_exception.cpp + * @bried Java ライクな Exception を扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + +#include +#include + +#include + + +namespace scpp +{ + + //////////////////////////////////////////////////////////////////////////// + // + // Throwable + // + + /** + * 最後に発生した errno に対応するメッセージを持つ Throwable を構築します。 + * エラーメッセージを取得できない場合、空文字がエラーメッセージに設定されます。 + */ + Throwable::Throwable() noexcept : message(sc_get_errmsg(NULL, 0, sc_get_errno())) + { + // NOP + } + + + /** + * コピーコンストラクタ。 + * + * @param t コピー元 + */ + Throwable::Throwable(const Throwable& t) noexcept : message(t.message) + { + // NOP + } + + + /** + * ムーブコンストラクタ。 + * + * @param t ムーブ元 + */ + Throwable::Throwable(Throwable&& t) noexcept : message(std::move(t.message)) + { + // NOP + } + + + /** + * 指定されたメッセージを持つ Throwable を構築します。 + * + * @param msg メッセージ + */ + Throwable::Throwable(const std::string& msg) noexcept : message(msg) + { + // NOP + } + + + /** + * コピー代入演算子 + * + * @param t 代入元 + */ + Throwable& Throwable::operator=(const Throwable& t) noexcept + { + this->message = t.message; + return (*this); + } + + + /** + * ムーブ代入演算子 + * + * @param t 代入元 + */ + Throwable& Throwable::operator=(Throwable&& t) noexcept + { + this->message = std::move(t.message); + return (*this); + } + + + /** + * デストラクタ。 + */ + Throwable::~Throwable() noexcept + { + // NOP + } + + + /** + * エラーメッセージを返します。 + * + * @return エラーメッセージ + */ + const char* Throwable::what() const noexcept + { + return message.c_str(); + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // Exception + // + + /** + * Exception を構築します。 + */ + Exception::Exception() noexcept : Throwable() + { + // NOP + } + + + /** + * コピーコンストラクタ。 + * + * @param t コピー元 + */ + Exception::Exception(const Exception& t) noexcept : Throwable(t) + { + // NOP + } + + + /** + * ムーブコンストラクタ。 + * + * @param t ムーブ元 + */ + Exception::Exception(Exception&& t) noexcept : Throwable(t) + { + // NOP + } + + + /** + * 指定されたメッセージを持つ Exception を構築します。 + * + * @param msg メッセージ + */ + Exception::Exception(const std::string& msg) noexcept : Throwable(msg) + { + // NOP + } + + + /** + * コピー代入演算子 + * + * @param t 代入元 + */ + Exception& Exception::operator=(const Exception& t) noexcept + { + Throwable::operator=(t); + return (*this); + } + + + /** + * ムーブ代入演算子 + * + * @param t 代入元 + */ + Exception& Exception::operator=(Exception&& t) noexcept + { + Throwable::operator=(t); + return (*this); + } + + + /** + * デストラクタ。 + */ + Exception::~Exception() noexcept + { + // NOP + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // Error + // + + /** + * Error を構築します。 + */ + Error::Error() noexcept : Throwable() + { + // NOP + } + + + /** + * コピーコンストラクタ。 + * + * @param t コピー元 + */ + Error::Error(const Error& t) noexcept : Throwable(t) + { + // NOP + } + + + /** + * ムーブコンストラクタ。 + * + * @param t ムーブ元 + */ + Error::Error(Error&& t) noexcept : Throwable(t) + { + // NOP + } + + + /** + * 指定されたメッセージを持つ Error を構築します。 + * + * @param msg メッセージ + */ + Error::Error(const std::string& msg) noexcept : Throwable(msg) + { + // NOP + } + + + /** + * コピー代入演算子 + * + * @param t 代入元 + */ + Error& Error::operator=(const Error& t) noexcept + { + Throwable::operator=(t); + return (*this); + } + + + /** + * ムーブ代入演算子 + * + * @param t 代入元 + */ + Error& Error::operator=(Error&& t) noexcept + { + Throwable::operator=(t); + return (*this); + } + + + /** + * デストラクタ。 + */ + Error::~Error() noexcept + { + // NOP + } + +} + diff --git a/modules/libscpp/test/Makefile b/modules/libscpp/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libscpp/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/Makefile b/Makefile index e44ba18..7bbaeb3 100644 --- a/Makefile +++ b/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/config.mk b/config.mk index 831a0c2..bd4eb88 100644 --- a/config.mk +++ b/config.mk @@ -53,3 +53,7 @@ # LIBS += -lpthread -lrt + +CFLAGS += -DSC_MEMORY_MANAGE=1 +CFLAGS += -DSC_MEMORY_DUMP_LEAK=1 + diff --git a/mk/base-auto.mk b/mk/base-auto.mk index ce970ff..fc9f523 100644 --- a/mk/base-auto.mk +++ b/mk/base-auto.mk @@ -26,6 +26,44 @@ LINK = $(CXX) endif + +# ------------------------------------------------------------------------------ +# ターゲットが ut.exe の場合の設定 +# +# 1. NDEBUG, NDEBUG を常に有効に設定する。 +# 2. SRCDIR に、../src を追加する。 +# 3. INCLUDES に、../include を追加する。 +# 4. DEFINE に -DUNITTEST -DNDEBUG -DDEBUG を追加する。 +# ------------------------------------------------------------------------------ +ifeq ($(strip $(TARGET)),ut.exe) +DEBUG = 1 +NDEBUG = 1 +SRCDIR += ../src +INCLUDES += -I../include +DEFINE += -DUNITTEST -DNDEBUG -DDEBUG +endif + + +ifeq ($(strip $(NDEBUG)),) +# ------------------------------------------------------------------------------ +# NDEBUG が無効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする +# ------------------------------------------------------------------------------ +CFLAGS += $(OPTIMIZATION) +CXXFLAGS += $(OPTIMIZATION) + +else +# ------------------------------------------------------------------------------ +# NDEBUG が有効な場合の設定 +# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする +# ------------------------------------------------------------------------------ +DEFINE += -DENABLED_MEMORY_MANAGE +CFLAGS += $(DEBUG_OPTIONS) +CXXFLAGS += $(DEBUG_OPTIONS) +LDFLAGS += $(DEBUG_LDFLAGS) + +endif + # ------------------------------------------------------------------------------ # CFLAGS, CXXFLAGS, LDFLAGS 設定 # ------------------------------------------------------------------------------ @@ -41,38 +79,3 @@ CXXFLAGS += $(DEFINE) CXXFLAGS += $(DEPENDS_OPTIONS) -# ------------------------------------------------------------------------------ -# ターゲットが ut.exe の場合の設定 -# -# 1. DEBUG を常に有効に設定する。 -# 2. SRCDIR に、../src を追加する。 -# 3. INCLUDES に、../include を追加する。 -# 4. DEFINE に -DUNITTEST を追加する。 -# ------------------------------------------------------------------------------ -ifeq ($(strip $(TARGET)),ut.exe) -DEBUG = 1 -SRCDIR += ../src -INCLUDES += -I../include -DEFINE += -DUNITTEST -endif - - -ifeq ($(strip $(DEBUG)),) -# ------------------------------------------------------------------------------ -# DEBUG が無効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の OPTIMIZATION を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(OPTIMIZATION) -CXXFLAGS += $(OPTIMIZATION) - -else -# ------------------------------------------------------------------------------ -# DEBUG が有効な場合の設定 -# CFLAGS, CXXFLAGS, LDFLAGS の DEBUG_OPTIONS を有効にする -# ------------------------------------------------------------------------------ -CFLAGS += $(DEBUG_OPTIONS) -CXXFLAGS += $(DEBUG_OPTIONS) -LDFLAGS += $(DEBUG_LDFLAGS) - -endif - diff --git a/mk/base-conf.mk b/mk/base-conf.mk index 790f571..81c9e11 100644 --- a/mk/base-conf.mk +++ b/mk/base-conf.mk @@ -79,3 +79,4 @@ DEBUG_LDFLAGS += --coverage DEBUG_LDFLAGS += -g3 -ggdb + diff --git a/modules/Makefile b/modules/Makefile index 2e43e7b..69cad55 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -12,7 +12,7 @@ RULEDIR ?= $(TOPDIR)/mk NAME = TARGET = $(NAME) -SUBDIRS = libcalc calc +SUBDIRS = libsc libscpp calc USE_SO_VERSION = # ------------------------------------------------------------------------------ @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk diff --git a/modules/calc/Makefile b/modules/calc/Makefile index da87bec..0cc307b 100644 --- a/modules/calc/Makefile +++ b/modules/calc/Makefile @@ -20,6 +20,7 @@ # *-conf.mk : 設定 # *-auto.mk : 自動設定 # ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk include $(RULEDIR)/*-cmd.mk include $(RULEDIR)/*-conf.mk include $(RULEDIR)/*-auto.mk @@ -32,7 +33,7 @@ CFLAGS += CXXFLAGS += LDFLAGS += -LIBS += -L$(TOPDIR)/lib -lcalc +LIBS += -L$(TOPDIR)/lib -lsc CLEAN_FILES += CLEAN_DIRS += diff --git a/modules/calc/src/main.c b/modules/calc/src/main.c index 4265469..b713c16 100644 --- a/modules/calc/src/main.c +++ b/modules/calc/src/main.c @@ -1,14 +1,85 @@ #include -#include "calc.h" +#include +#include +#include + +void mhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("m line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void fhandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("f line=%d, size=%d, %s\n", meminfo->line, meminfo->size, msg); +} +void ehandler(sc_memory* meminfo, const char* msg) +{ + (void) meminfo; + printf("e %s\n", msg); +} + + + +int func(void* v) +{ + int* val = (int*) v; + printf("call %d\n", *val); + int* x = (int*) malloc(sizeof(int)); + *x = *val; + + thrd_sleep(&(struct timespec){.tv_sec=1}, NULL); + + free(x); + return 0; +} + +int counter = 0; +void entries(sc_memory* entry) +{ + counter++; + (void) entry; +} int main(void) { - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); +//sc_memory_mhandler = mhandler; +//sc_memory_fhandler = fhandler; +//sc_memory_ehandler = ehandler; + +/* + char* ptr = malloc(10); + *ptr = 'A'; + printf("%c\n", *ptr); + char* ptr2 = (char*) realloc(ptr, 20); + ptr2[1] = 'B'; + printf("%c\n", *ptr); +// free(ptr2); + + char* ptr3 = (char*) malloc(3); + *ptr3 = 'X'; + + int* ptr4 = (int*) malloc(5); + *ptr4 = 0x1234567; +*/ + thrd_t t[100]; + int v[100]; + for (int i = 0; i < 100; i++) + { + v[i] = i; + thrd_create(&t[i], func, &v[i]); + } + for (int i = 0; i < 100; i++) + { + thrd_join(t[i], NULL); + } + +// sc_memory_entries(sc_memory_dump_entry); + sc_memory_entries(entries); + printf("counter = %d\n", counter); + return 0; } diff --git a/modules/libcalc/Makefile b/modules/libcalc/Makefile deleted file mode 100644 index e9977e1..0000000 --- a/modules/libcalc/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = libcalc -TARGET = $(NAME).so -SUBDIRS = test -USE_SO_VERSION = y - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/include/calc.h b/modules/libcalc/include/calc.h deleted file mode 100644 index e28d00f..0000000 --- a/modules/libcalc/include/calc.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CALC_H -#define CALC_H - - -int add(int a, int b); - -#endif - diff --git a/modules/libcalc/src/calc.c b/modules/libcalc/src/calc.c deleted file mode 100644 index 059d557..0000000 --- a/modules/libcalc/src/calc.c +++ /dev/null @@ -1,6 +0,0 @@ -#include - -int add(int a, int b) -{ - return (a + b); -} diff --git a/modules/libcalc/test/Makefile b/modules/libcalc/test/Makefile deleted file mode 100644 index dc6af03..0000000 --- a/modules/libcalc/test/Makefile +++ /dev/null @@ -1,47 +0,0 @@ -# ============================================================================== -# Makefile -# ============================================================================== -# -# TOPDIR : トップディレクトリ -# RULEDIR : Meke のルール一式が格納されているディレクトリ -# NAME : モジュール名 (拡張子を含めないこと) -# TARGET : モジュールファイル名 (拡張子を含めること) -# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) -# -TOPDIR ?= ../../.. -RULEDIR ?= $(TOPDIR)/mk -NAME = ut.exe -TARGET = $(NAME) -SUBDIRS = -USE_SO_VERSION = - -# ------------------------------------------------------------------------------ -# *-cmd.mk : コマンド -# *-conf.mk : 設定 -# *-auto.mk : 自動設定 -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-cmd.mk -include $(RULEDIR)/*-conf.mk -include $(RULEDIR)/*-auto.mk -# ------------------------------------------------------------------------------ -# -# 以下、オプションを適宜変更してください。 -# - -INCLUDES += -I$(TOPDIR)/include -CFLAGS += -CXXFLAGS += -LDFLAGS += -LIBS += -L$(TOPDIR)/lib - -CLEAN_FILES += -CLEAN_DIRS += - -.DEFAULT_GOAL := all - -# ------------------------------------------------------------------------------ -# *-rule : ルール -# ------------------------------------------------------------------------------ -include $(RULEDIR)/*-rule.mk -# ------------------------------------------------------------------------------ - diff --git a/modules/libcalc/test/src/test.c b/modules/libcalc/test/src/test.c deleted file mode 100644 index 4265469..0000000 --- a/modules/libcalc/test/src/test.c +++ /dev/null @@ -1,15 +0,0 @@ -#include - -#include "calc.h" - - -int main(void) -{ - int a = 5; - int b = 100; - int c = add(a, b); - printf("%d\n", c); - return 0; -} - - diff --git a/modules/libsc/Makefile b/modules/libsc/Makefile new file mode 100644 index 0000000..17593cd --- /dev/null +++ b/modules/libsc/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libsc +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/include/sc.h b/modules/libsc/include/sc.h new file mode 100644 index 0000000..04e470e --- /dev/null +++ b/modules/libsc/include/sc.h @@ -0,0 +1,15 @@ +/** + * @file sc.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_H +#define SC_H + +#include +#include +#include + +#endif /* SC_H */ + diff --git a/modules/libsc/include/sc_compiler.h b/modules/libsc/include/sc_compiler.h new file mode 100644 index 0000000..018b08e --- /dev/null +++ b/modules/libsc/include/sc_compiler.h @@ -0,0 +1,48 @@ +/** + * @file sc_compiler.h + * @bried C言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + */ +#ifndef SC_COMPILER_H +#define SC_COMPILER_H +#ifndef __cplusplus + + +#if defined(__STDC_VERSION__) +#if (__STDC_VERSION__ >= 199901L) +/* ----- C99 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (0) +#define IS_SUPPORTED_CPP17 (0) +#define IS_SUPPORTED_CPP14 (0) +#define IS_SUPPORTED_CPP11 (0) +#define IS_SUPPORTED_C17 (__STDC_VERSION__ >= 201710L) +#define IS_SUPPORTED_C11 (__STDC_VERSION__ >= 201112L) +#define IS_SUPPORTED_C99 (__STDC_VERSION__ >= 199901L) + +#else +/* ----- C99 以前の場合はエラーとする */ +#error "unsupported c version, please use c99 or later" + +#endif /* (__STDC_VERSION__ >= 19901L) */ + +#else +#error "unsupported c version, please use c99 or later (not found __STDC_VERSION__)" + +#endif /* defined(__STDC_VERSION__) */ + + +#endif /* !__cplusplus */ +#endif /* SC_COMPILER_H */ diff --git a/modules/libsc/include/sc_errno.h b/modules/libsc/include/sc_errno.h new file mode 100644 index 0000000..43aaa8d --- /dev/null +++ b/modules/libsc/include/sc_errno.h @@ -0,0 +1,45 @@ +/** + * @file sc_errno.h + * @bried エラー番号、エラーメッセージを扱うヘッダーファイル。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_ERRNO_H +#define SC_ERRNO_H + +#include +#include +#include + +#include +#include + + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 最後に発生したエラー番号を取得します。 + * @return エラー番号 + */ +#define sc_get_errno() (errno) + + +/** + * エラー番号を設定します。 + * @param errnum エラー番号 + */ +#define sc_set_errno(errnum) (errno = errnum) + + +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum); + + +#ifdef __cplusplus +} +#endif + +#endif // SC_ERRNO_H diff --git a/modules/libsc/include/sc_memory.h b/modules/libsc/include/sc_memory.h new file mode 100644 index 0000000..65b1a7c --- /dev/null +++ b/modules/libsc/include/sc_memory.h @@ -0,0 +1,93 @@ +/** + * @file sc_memory.h + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_MEMORY_H +#define SC_MEMORY_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/** + * 管理メモリ種別を表すための識別マーク。 + */ +#define SC_MEMORY_MARK_HEAD (0x55AA55A0) +#define SC_MEMORY_MARK_MASK (0xFFFFFFFC) +typedef enum { + SC_MEMORY_DELETED = SC_MEMORY_MARK_HEAD|0x0, //< メモリが解放されている + SC_MEMORY_ALLOCATED = SC_MEMORY_MARK_HEAD|0x1, //< メモリが確保されている + SC_MEMORY_ALLOCATED_NEW = SC_MEMORY_MARK_HEAD|0x2, //< メモリが new により確保されている + SC_MEMORY_ALLOCATED_NEW_ARRAY = SC_MEMORY_MARK_HEAD|0x3, //< メモリが new[] により確保されている +} sc_memory_mark; + +/** + * 指定されたメモリ管理用種別マークが正しいかを判定します。 + * + * @param mark 種別マーク + * @return true/false (管理されているメモリ/管理されていないメモリ) + */ +#define sc_memory_is_valid(mark) ((mark & SC_MEMORY_MARK_MASK) == SC_MEMORY_MARK_HEAD) + + +/** + * メモリ管理情報 + */ +typedef struct sc_memory_ +{ + const char* file; //< メモリを確保したファイル名 + int line; //< メモリを確保した行番号 + const char* func; //< メモリを確保した関数名 + int size; //< サイズ + sc_memory_mark _mark; // 確保したメモリの種別マーク + struct sc_memory_* _prev; // 前の管理メモリへのポインタ + struct sc_memory_* _next; // 後の管理メモリへのポインタ + void* data; //< データ領域へのポインタ +} sc_memory; + +// ハンドラ +extern void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg); +extern void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg); + +/// 本来の関数 +void* sc_raw_malloc ( size_t size); +void* sc_raw_calloc (size_t nmemb, size_t size); +void* sc_raw_realloc(void* ptr, size_t size); +void sc_raw_free (void* ptr); + +// メモリ管理用関数 +void* sc_malloc ( size_t size, const char* file, int line, const char* func); +void* sc_calloc (size_t nmemb, size_t size, const char* file, int line, const char* func); +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func); +void sc_free (void* ptr); + +bool sc_memory_entries(void (*callback)(sc_memory* entry)); +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)); +void sc_memory_dump_entry(sc_memory* entry); +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func); +void sc_memory_free(void* ptr); + +const char* sc_memory_markstr(sc_memory_mark mark); + + +#ifdef SC_MEMORY_MANAGE +#define malloc( size) sc_malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) sc_calloc( nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) sc_realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) sc_free(ptr) +#endif // SC_MEMORY_MANAGE + + +#ifdef __cplusplus +} +#endif + +#endif // SC_MEMORY_H diff --git a/modules/libsc/include/sc_os.h b/modules/libsc/include/sc_os.h new file mode 100644 index 0000000..ffc0d71 --- /dev/null +++ b/modules/libsc/include/sc_os.h @@ -0,0 +1,99 @@ +/** + * @file sc_os.h + * @bried OS判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * 次の OS を判定するマクロが定義されます。 + * - IS_WINDOWS + * - IS_LINUX + * - IS_UNIX + * - IS_BSD + * - IS_MAC + * - IS_VXWORKS + */ +#ifndef SC_OS_H +#define SC_OS_H + + +//////////////////////////////////////////////////////////////////////////////// +// +// Windows 判定 +// Windows の場合、windows.h と winsock2.h が include されます。 +// +#if defined(WIN32) || defined(_WIN32) || defined(__WIN32) || defined(__WIN32__) \ + || defined(WIN64) || defined(_WIN64) || defined(__WIN64) || defined(__WIN64__) +#define IS_WINDOWS (1) +// dMC にて winsock2.h を使用する場合、_WINSOCKAPI_ の定義が必要 +// 詳細は、下記 URL 参照 +// http://www.digitalmars.com/d/archives/c++/idde/326.html +#ifdef __DMC__ +#define _WINSOCKAPI_ +#include +#endif +#ifndef _WIN32_WINNT +#define _WIN32_WINNT 0x0501 +#endif +#include +#include +#else +#define IS_WINDOWS (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// Linux 判定 +// +#if defined(linux) || defined(__linux) || defined(__linux__) +#define IS_LINUX (1) +#else +#define IS_LINUX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// UNIX互換判定 +// +#if defined(unix) || defined(__unix) || defined(__unix__) +#define IS_UNIX (1) +#else +#define IS_UNIX (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// BSD系判定 +// +#if defined(BSD) || defined(_BSD) || defined(__BSD) +#define IS_BSD (1) +#else +#define IS_BSD (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// MAC判定 +// +#if defined(mac) || defined(MAC) || defined(_MAC) +#define IS_MAC (1) +#else +#define IS_MAC (0) +#endif + + +//////////////////////////////////////////////////////////////////////////////// +// +// VxWorks 判定 +// +#if defined(VXWORKS) || defined(VxWorks) +#define IS_VXWORKS (1) +#else +#define IS_VXWORKS (0) +#endif + + +#endif // SC_OS_H diff --git a/modules/libsc/include/sc_threads.h b/modules/libsc/include/sc_threads.h new file mode 100644 index 0000000..0fb03ba --- /dev/null +++ b/modules/libsc/include/sc_threads.h @@ -0,0 +1,74 @@ +/** + * @file sc_thread.h + * @bried スレッド用ヘッダ + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SC_THREAD_H +#define SC_THREAD_H + +#include + +#ifdef __STDC_NO_THREADS__ +// スレッドの完全サポートがない + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +#define thread_local +#define _Thread_local + +enum +{ + thrd_success, //< 成功を示します。 + thrd_nomem, //< メモリ不足で失敗したことを示します。 + thrd_timedout, //< タイムアウト + thrd_busy, //< リソースがいい知事的に利用できない。 + thrd_error //< エラー発生 +}; + +typedef int thrd_t; +typedef int (*thrd_start_t)(void*); + +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg); +int thrd_equal(thrd_t lhs, thrd_t rhs); +thrd_t thrd_current(void); +int thrd_sleep(const struct timespec* duration, struct timespec* remaining); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +enum +{ + mtx_plain, //< シンプルで非再帰的なミューテックスが作成されます。 + mtx_recursive, //< 再帰的ミューテックスが作成されます。 + mtx_timed //< タイムアウトをサポートする非再帰的ミューテックスが作成されます。 +}; + +#define ONCE_FLAG_INIT (false) +typedef bool mtx_t; +#define call_once(flag, func) \ + do { if (!*(flag)) { func(); *(flag) = true; } while (0) + +int mtx_init(mtx_t* mutex, int type); +int mtx_lock(mtx_t* mutex); +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point); +int mtx_trylock(mtx_t* mutex); +int mtx_unlock(mtx_t* mutex); +void mtx_unlock(mtx_t* mutex); + + +#else +// スレッドを完全サポートしている +#include + +#endif // __STDC_NO_THREADS___ + +#endif // SC_THREAD_H diff --git a/modules/libsc/src/.sc_errno.c.swp b/modules/libsc/src/.sc_errno.c.swp new file mode 100644 index 0000000..03eed7d --- /dev/null +++ b/modules/libsc/src/.sc_errno.c.swp Binary files differ diff --git a/modules/libsc/src/sc_errno.c b/modules/libsc/src/sc_errno.c new file mode 100644 index 0000000..5da2c85 --- /dev/null +++ b/modules/libsc/src/sc_errno.c @@ -0,0 +1,72 @@ +/** + * @file sc_errno.c + * @bried エラー番号、エラーメッセージを扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#ifndef __STDC_WANT_LIB_EXT1__ +#define __STDC_WANT_LIB_EXT1__ (1) +#endif + +#include + +#include +#include + + +#ifndef MAXMSG +#define MAXMSG (256) +#endif + +static thread_local char sc_error_message[MAXMSG]; + +/** + * エラー番号に対応するメッセージを取得します。 + * エラーメッセージは、buf に格納されます。 + * + * buf が NULL または、 buflen が 0 の場合、 + * ライブラリ内で保持しているスレッドローカル変数に + * メッセージが格納され、そのポインタを返します。 + * + * @param buf エラーメッセージを格納するバッファ + * @param buflen バッファサイズ + * @param errnum エラー番号 + * @return エラーメッセージへのポインタ + */ +const char* sc_get_errmsg(char* buf, size_t buflen, int errnum) +{ + char* bufptr = buf; + size_t bufptrlen = buflen; + if ((buf == NULL) || (buflen <= 0)) + { + bufptr = sc_error_message; + bufptrlen = MAXMSG; + } + memset(bufptr, '\0', bufptrlen); + +#ifdef __STDC_LIB_EXT1__ + // C++ 標準の strerror_s が利用可能 + errno_t ret = strerror_s(bufptr, bufptrlen, errnum); + +#elif (defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)) \ + ||(defined(__XOPEN_SOURCE) && (__XOPEN_SOURCE >= 600)) + // XSI準拠 strerror_r が利用可能 + int ret = strerror_r(errnum, bufptr, bufptrlen); + +#else + // 上記以外の場合 ANSI 準拠 strerror(errnum) を使用する。 + char* tmpmsg = strerror(errnum); + strncpy(bufptr, tmpmsg, bufptrlen); + bufptr[bufptrlen - 1] = '\0'; + int ret = 0; + +#endif + if (ret == 0) + { + return bufptr; + } + return ""; +} + + diff --git a/modules/libsc/src/sc_memory.c b/modules/libsc/src/sc_memory.c new file mode 100644 index 0000000..6f154b4 --- /dev/null +++ b/modules/libsc/src/sc_memory.c @@ -0,0 +1,739 @@ +/** + * @file sc_memory.c + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ + +#include +#include +#include +#include + + +// ここでは常に本来の malloc, free を利用するため SC_MEMORY_MANAGE を無効化する。 +#ifdef SC_MEMORY_MANAGE +#undef SC_MEMORY_MANAGE +#endif + +#ifndef SC_MEMORY_DUMP_LEAK +#define SC_MEMORY_DUMP_LEAK (0) +#endif + +// #include +#include +#include + + +//////////////////////////////////////////////////////////////////////////////// +// +// 定数定義 +// + +// 管理領域確保時のパディング +#define PADDING (sizeof(void*) * 2) +#define TO_ASCII(c) (((0x20 <= c) && (c < 0x7F)) ? c : '.'); + +/** 16進数文字 */ +static const char HEX_CHARS[] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// 変数定義 +// + +// 外部公開変数 +void (*sc_memory_ahandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_fhandler)(sc_memory* meminfo, const char* msg) = NULL; +void (*sc_memory_ehandler)(sc_memory* meminfo, const char* msg) = NULL; + +// 以下、内部専用 +static sc_memory sc_memory_head; +static sc_memory sc_memory_tail; +static sc_memory sc_memory_error; + +static thread_local bool sc_memory_nolock = false; +static once_flag sc_memory_once_flag = ONCE_FLAG_INIT; +static mtx_t sc_memory_mutex; + + +/** メモリの種別マークに対応する文字列リスト */ +static const char* SC_MEMORY_MARK_STRINGS[] = { + "deleted ", + "allocated ", + "allocated(new) ", + "allocated(new[])" +}; + + +//////////////////////////////////////////////////////////////////////////////// +// +// プロトタイプ宣言 (内部関数) +// + +static void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, + const char* file, int line, const char* func); +static void sc_memory_do_init(void); +static void sc_memory_init(void); +static bool sc_memory_add(sc_memory* entry); +static bool sc_memory_remove(sc_memory* entry); +static void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size); +static void sc_memory_dump_leak(void); +static void sc_memory_exec_ahandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_fhandler(sc_memory* entry, const char* msg); +static void sc_memory_exec_ehandler(sc_memory* entry, const char* msg); +// +// スレッド対応用関数 +// +static bool sc_memory_mtx_lock(sc_memory* entry); +static bool sc_memory_mtx_unlock(sc_memory* entry); + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 (本来の関数) +// + + +/** + * 本来の malloc を実行します。 + * + * @param size 確保するメモリサイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_malloc(size_t size) +{ + return malloc(size); +} + + +/** + * 本来の calloc を実行します。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @return 割り当てられたメモリに対するポインタ + */ +void* sc_raw_calloc(size_t nmemb, size_t size) +{ + return calloc(nmemb, size); +} + + +/** + * 本来の realloc を実行します。 + * + * @param ptr メモリブロックサイズを変更するポインタ + * @param size 変更するサイズ + * @return 再割り当てされたメモリに対するポインタ + */ +void* sc_raw_realloc(void* ptr, size_t size) +{ + return realloc(ptr, size); +} + + +/** + * 本来の free を実行します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_raw_free(void* ptr) +{ + free(ptr); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 公開関数実装 +// + + +/** + * 指定されたサイズのメモリを確保します。 + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_malloc(size_t size, const char* file, int line, const char* func) +{ + void* ptr = sc_memory_allocate(NULL, size, SC_MEMORY_ALLOCATED, file, line, func); + return ptr; +} + + +/** + * 指定されたメモリサイズのメモリを確保します。 + * 確保したメモリの中身は 0x00 でクリアされます。 + * + * @param nmemb 確保するメモリの要素数 + * @param size 1つのメモリ要求サイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_calloc(size_t nmemb, size_t size, const char* file, int line, const char* func) +{ + size_t n = nmemb * size; + void* ptr = sc_memory_allocate(NULL, n, SC_MEMORY_ALLOCATED, file, line, func); + if (ptr != NULL) + { + memset(ptr, 0x00, n); + } + return ptr; +} + + +/** + * ポインタが示すメモリブロックのサイズを変更します。 + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_realloc(void* ptr, size_t size, const char* file, int line, const char* func) +{ + void* nptr = sc_memory_allocate(ptr, size, SC_MEMORY_ALLOCATED, file, line, func); + return nptr; +} + + +/** + * 指定されたメモリを解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_free(void* ptr) +{ + sc_memory_free(ptr); +} + + +/** + * 指定された callback に現在管理しているメモリが順次渡されます。 + * callback 内で malloc, free などのメモリ操作は実施不可です。 + * + * @param callback コールバック関数 + * @return true/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_entries(void (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + callback(entry); + entry = entry->_next; + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + +/** + * callbaack が true を返すメモリを解放します。 + * + * @param entry メモリエントリ + * @return ture/false (処理成功/ロック獲得失敗) + */ +bool sc_memory_freeif(bool (*callback)(sc_memory* entry)) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(NULL); + if (!result) { return false; } + sc_memory_nolock = true; // ロック無効 + + sc_memory* entry = sc_memory_head._next; + while (entry != &sc_memory_tail) + { + bool execfree = callback(entry); + entry = entry->_next; + if (execfree) + { + sc_free(entry->_prev); + } + } + + sc_memory_nolock = false; // ロック無効解除 + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(NULL); + return result; +} + + + +/** + * 指定されたメモリの情報をダンプします。 + * + * ``` + * 使用例) + * sc_memory_entries(sc_memory_dump_entry); + * ``` + * + * @param entry メモリエントリ + */ +void sc_memory_dump_entry(sc_memory* entry) +{ + printf("%-15s:%05d:%-15s (%5d) %s", + entry->file, + entry->line, + entry->func, + entry->size, + sc_memory_markstr(entry->_mark)); + + + // 16進数ダンプ出力 + char buf[8 * 3]; + sc_memory_dump_data(buf, sizeof(buf), entry->data, entry->size); + printf(" %s", buf); + + // ASCII 出力 + sc_memory_dump_data_ascii(buf, (sizeof(buf) / 3), entry->data, entry->size); + printf(" | %s\n", buf); +} + + +/** + * realloc(ptr, size) と同様の方法でメモリを確保します。 + * + * @param ptr メモリサイズを変更するメモリへのポインタ + * @param size 確保するメモリサイズ + * @param mark メモリ確保情報を示すマーク + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + * @return 確保したメモリへのポインタ + */ +void* sc_memory_allocate(void* ptr, size_t size, sc_memory_mark mark, const char* file, int line, const char* func) +{ + if (size == 0) + { // size == 0 の場合は、free と等価 + sc_memory_free(ptr); + return NULL; + } + + sc_memory* entry = (sc_memory*) sc_raw_malloc(size + sizeof(sc_memory) + PADDING); + if (entry == NULL) + { // メモリ確保失敗 + errno = ENOMEM; + sc_memory_set_entry(&sc_memory_error, mark, size, file, line, func); + sc_memory_exec_ehandler(&sc_memory_error, "allocate error"); + return NULL; + } + + if (ptr != NULL) + { + sc_memory* old_entry = (sc_memory*) ptr; + switch (old_entry->_mark) + { + case SC_MEMORY_DELETED: // 削除済みメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての realloc + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての realloc + // 管理メモリ (エラー) + errno = EINVAL; + sc_memory_exec_ehandler(old_entry, "realloc error"); + return NULL; + case SC_MEMORY_ALLOCATED: + default: + // ptr 領域のデータを移動し、解放する。 + memmove((entry + 1), ptr, size); + sc_memory_free(ptr); + break; + } + } + + // 基本設定 + sc_memory_set_entry(entry, mark, size, file, line, func); + (void) sc_memory_add(entry); + return (entry->data); +} + + +/** + * 指定されたポインタの指すメモリ領域を解放します。 + * + * @param ptr 解放するメモリへのポインタ + */ +void sc_memory_free(void* ptr) +{ + if (ptr == NULL) + { // NULL ポインタに対しては何もしない。 + return; + } + + sc_memory* entry = (sc_memory*) ptr; + entry--; + switch (entry->_mark) + { + case SC_MEMORY_ALLOCATED: + // 管理メモリ + (void) sc_memory_remove(entry); + entry->_mark = SC_MEMORY_DELETED; + entry->size = 0; + sc_raw_free(entry); + break; + case SC_MEMORY_DELETED: // 削除済みメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW: // new で確保したメモリに対しての free + case SC_MEMORY_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリに対しての free + break; + default: + // 管理外メモリ + sc_raw_free(ptr); + break; + } +} + + + +/** + * 指定されたメモリ種別マークの文字列表現を返します。 + * + * @param mark 種別マーク + * @return 指定された種別マークの文字列表現 + */ +const char* sc_memory_markstr(sc_memory_mark mark) +{ + if (sc_memory_is_valid(mark)) + { // 管理されている種別マークに対応する文字列を返す。 + return SC_MEMORY_MARK_STRINGS[(mark & 0x03)]; + } + return "unmanaged "; +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// 内部関数 +// + +/** + * 指定された entry に、各値を設定します。 + * + * @param entry エントリ + * @param mark 種別マーク + * @param size メモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数 + */ +static +void sc_memory_set_entry(sc_memory* entry, sc_memory_mark mark, size_t size, const char* file, int line, const char* func) +{ + entry->size = size; + entry->file = file; + entry->line = line; + entry->func = func; + entry->_mark = mark; + entry->data = (entry + 1); + entry->_prev = NULL; + entry->_next = NULL; +} + + + + +/** + * メモリ管理を初期化します。 + * 本関数は、sc_memory_init より一度だけ実行されます。 + */ +static +void sc_memory_do_init(void) +{ + int is_success; + + // mutex (for メモリ管理) + is_success = mtx_init(&sc_memory_mutex, mtx_plain); + if (is_success != thrd_success) { perror("can't init mutex"); } + + sc_memory_set_entry(&sc_memory_head , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_tail , SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_set_entry(&sc_memory_error, SC_MEMORY_DELETED, 0, NULL, 0, NULL); + sc_memory_head._prev = sc_memory_head._next = &sc_memory_tail; + sc_memory_tail._prev = sc_memory_tail._next = &sc_memory_head; + + if (SC_MEMORY_DUMP_LEAK != 0) + { + atexit(sc_memory_dump_leak); + } +} + + + +/** + * 指定されたエントリを追加します。 + * 通常 nolock は、false を指定します。 + * + * @param entry 追加するエントリ + */ +static +bool sc_memory_add(sc_memory* entry) +{ + sc_memory_init(); + + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_next = &sc_memory_tail; + entry->_prev = sc_memory_tail._prev; + sc_memory_tail._prev->_next = entry; + sc_memory_tail._prev = entry; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_ahandler(entry, "allocate"); + return result; +} + + +/** + * 指定されたエントリを削除します。 + * + * @param entry エントリ + */ +static +bool sc_memory_remove(sc_memory* entry) +{ + // ■ ----- LOCK ----- + bool result = sc_memory_mtx_lock(entry); + if (!result) { return false; } + + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + // ■ ----- UNLOCK ----- + result = sc_memory_mtx_unlock(entry); + + sc_memory_exec_fhandler(entry, "free"); + return result; +} + + +/** + * 指定されたバッファにデータのダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 * 3) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen / 3; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[(idx * 3) + 0] = HEX_CHARS[(*dptr >> 4) & 0x0F]; + buf[(idx * 3) + 1] = HEX_CHARS[(*dptr ) & 0x0F]; + buf[(idx * 3) + 2] = ' '; + dptr++; + } + for (; idx < len; idx++) + { + buf[(idx * 3) + 0 ] = '-'; + buf[(idx * 3) + 1 ] = '-'; + buf[(idx * 3) + 2 ] = ' '; + } + buf[(idx - 1) * 3 + 2] = '\0'; +} + + +/** + * 指定されたバッファにデータのASCII形式ダンプ情報を格納します。 + * ダンプ情報は、バッファサイズ に併せて調整されます。 + * + * 例) 16 byte のダンプ情報を出力する場合は、バッファサイズ (16 + 1) を指定ください。 + * バッファの最後には、'\0' が入ります。 + * + * @param buf ダンプデータ(文字列表現)を格納するバッファ + * @param buflen バッファサイズ + * @param data データへのポインタ + * @param size データのサイズ + */ +static +void sc_memory_dump_data_ascii(char* buf, size_t buflen, void* data, size_t size) +{ + unsigned char* dptr = (unsigned char*) data; + int len = buflen - 1; + int dlen = ((int) size < len) ? (int) size : len; + + int idx = 0; + for (; idx < dlen; idx++) + { + buf[idx] = TO_ASCII(*dptr); + dptr++; + } + for (; idx < len; idx++) + { + buf[idx] = ' '; + } + buf[idx] = '\0'; +} + + +/** + * メモリリーク情報をダンプします。 + */ +static +void sc_memory_dump_leak(void) +{ + sc_memory_entries(sc_memory_dump_entry); +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ハンドラ実行ラッパー関数 +// + + +/** + * メモリ確保時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 確保したメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ahandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ahandler != NULL) + { + sc_memory_ahandler(entry, msg); + } +} + + +/** + * メモリ解放時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 解放するメモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_fhandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_fhandler != NULL) + { + sc_memory_fhandler(entry, msg); + } +} + + +/** + * エラー発生時のハンドラを実行します。 + * ハンドラが未登録の場合は何もしません。 + * + * @param entry 操作対象メモリエントリ + * @param msg メッセージ + */ +static +void sc_memory_exec_ehandler(sc_memory* entry, const char* msg) +{ + if (sc_memory_ehandler != NULL) + { + sc_memory_ehandler(entry, msg); + } +} + + +//////////////////////////////////////////////////////////////////////////////// +// +// Thread サポート +// + +/** + * メモリ管理を初期化します。 + * 実際の初期化処理は、一度だけ実行される sc_memory_do_init にて実施されます。 + */ +static +void sc_memory_init(void) +{ // sc_memory_do_init を1度だけ実行します。 + call_once(&sc_memory_once_flag, sc_memory_do_init); +} + + +/** + * mutex によるロックをかけます。 + * ロックに成功した場合、true を返します。 + * ロックに失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック成功/ロック失敗) + */ +static +bool sc_memory_mtx_lock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_lock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx lock error"); + sc_memory_exec_ehandler(entry, "mtx lock error"); + } + return result; +} + + +/** + * mutex によるロックを解除します。 + * ロック解除に成功した場合、true を返します。 + * ロック解除に失敗した場合、sc_memory_ehandler を実行し、false を返します。 + * + * @param entry 操作対象メモリの情報 + * @return true/false (ロック解除成功/ロック解除失敗) + */ +static +bool sc_memory_mtx_unlock(sc_memory* entry) +{ + // ロック無効 (sc_memory_entries, sc_memory_freeif 実行中) の場合、何もせず true を返す。 + if (sc_memory_nolock) { return true; } + + bool result = (mtx_unlock(&sc_memory_mutex) == thrd_success); + if (!result) + { + perror("mtx unlock error"); + sc_memory_exec_ehandler(entry, "mtx unlock error"); + } + return result; +} + diff --git a/modules/libsc/src/sc_threads.c b/modules/libsc/src/sc_threads.c new file mode 100644 index 0000000..cab53c1 --- /dev/null +++ b/modules/libsc/src/sc_threads.c @@ -0,0 +1,250 @@ +/** + * @file sc_threds.c + * @bried スレッドモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include + +#ifdef __STDC_NO_THREADS__ +// C11 対応している状態かつ、標準のスレッドが未サポート +// => スレッドを扱わないシステムとして、ダミー関数実装とする。 + + +//////////////////////////////////////////////////////////////////////////////// +// +// スレッド +// + +static thrd_t thrd_uniq_id = 0; /// ユニークなスレッドID生成用 +static thrd_t thrd_current_id = 0; /// 現在のスレッドID + + +/** + * 本来はスレッドを開始しますが、 + * ダミー実装として、指定された関数を呼び出します。 + * + * @param thr スレッド識別子 + * @param func 実行する関数 + * @param arg パラメータ + * @return thrd_success (固定) + */ +int thrd_create(thrd_t* thr, thrd_start_t func, void* arg) +{ + func(arg); + thrd_uniq_id++; + *thr = thrd_uniq_id; + return thrd_success; +} + + +/** + * 指定されたスレッドが同じスレッドを参照しているか否かを返します。 + * + * @param lhs 比較するスレッド1 + * @param rhs 比較するスレッド2 + * @return 非ゼロ/0 (同じ/異なる) + */ +int thrd_equal(thrd_t lhs, thrd_t rhs) +{ + return !(lhs == rhs); +} + + +/** + * 現在のスレッド識別子を返します。 + * + * @return 現在のスレッド識別子 + */ +thrd_t thrd_current(void) +{ + return thrd_current_id; +} + + +#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 199309L) +#include + +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + return nanosleep(duration, remaining); +} + +#else +/** + * 少なくとも duration が経過するまで、現在のスレッドの実行をブロックします。 + * 無視されない信号を受信すると、スリープが早期に再開される場合があります。 + * このような場合、remaining が NULL 出ない場合、残りの時間を指すオブジェクトが格納されます。 + * + * @param duration スリープする期間へのポインタ + * @param remaining 中断の残り時間を設定するオブジェクトへのポインタ + * @return 0/-1/そのた負値 (成功/シグナル発生/その他エラー) + */ +int thrd_sleep(const struct timespec* duration, struct timespec* remaining) +{ + // サポートしていない + return -2; +} + +#endif + + +/** + * スレッドの実行を再スケジュールするためのヒントを実装に提供し、 + * 他のスレッドを実行できるようにします。 + * ダミー実装は、何もしません。 + */ +void thrd_yield(void) +{ + // NOP +} + + +/** + * スレッドを終了します。 + */ +void thrd_exit(int res) +{ + (void) res; +} + + +/** + * 指定されたスレッドを現在の環境から切り離します。 + * スレッドが保持していたリソースは自動的に開放されます。 + * ダミー実装は、スレッド自体起動していないため、何もせず成功を返します。 + * + * @param thr スレッド識別子 + * @return thrd_success (固定) + */ +int thrd_detach(thrd_t thr) +{ + (void) thr; + return thrd_success; +} + + +/** + * 本来はスレッドが終了するまで待ちますが、 + * ダミー実装は、スレッド自体起動していないので、すぐに成功を返します。 + * + * @param thr スレッド識別子 + * @param res 結果コード + * @return thrd_success (固定) + */ +int thrd_join(thrd_t thr, int* res) +{ + if (res != NULL) + { + *res = thrd_success; + } + return thrd_success; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// ミューテックス +// + +#define MTX_TYPE(val) ((val >> 24) & 0xFF) +#define MTX_IS_MATCH_TYPE(val, type) ((MTX_TYPE(val) & type) == type) +static mtx_t mtx_uniq_id = 0; /// ユニークなミューテックスID生成用 + +/** + * ミューティックスオブジェクトを作成します。 + * + * @param mutex ミューテックス + * @param タイプ + * @return thrd_success (固定) + */ +int mtx_init(mtx_t* mutex, int type) +{ + mtx_uniq_id++; + *mutex = (mtx_uniq_id | (type << 24)); + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるまで、現在のスレッドをブロックします。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_lock(mtx_t* mutex) +{ + (void) mutex; + return thrd_success; +} + + +/** + * 指定されたミューテックスがロックされるか、指定された絶対カレンダー時点に達するまで + * 現在のスレッドをブロックします。 + * ミューテックスがタイムアウトをサポートしない場合、動作は未定義です。 + * + * @param mutex ミューテックス + * @return thrd_success/thrd_error + */ +int mtx_timedlock(mtx_t* restrict mutex, const struct timespec time_point) +{ + if (MTX_IS_MATCH_TYPE(*mutex, mtx_timed)) + { + return thrd_success; + } + return thrd_error; +} + + +/** + * 指定したミューテックスをブロックせずにロックしようとします。 + * ダミー実装では、mtx_lock と同じ動作となります。 + * + * @param mutex ミューテックス + * @return thrd_success (固定) + */ +int mtx_trylock(mtx_t* mutex) +{ + return mtx_lock(mutex); +} + + +/** + * 指定したミューテックスをアンロックします。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +int mtx_unlock(mtx_t* mutex) +{ + (void) mutex; + return shrd_success; +} + + +/** + * 指定したミューテックスを破棄します。 + * + * @param mutex ミューテックス + * @return thrd_success + */ +void mtx_unlock(mtx_t* mutex) +{ + (void) mutex; +} + + + +#endif // __STDC_NO_THREADS__ diff --git a/modules/libsc/test/Makefile b/modules/libsc/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libsc/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libsc/test/src/test.c b/modules/libsc/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libsc/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + + diff --git a/modules/libscpp/Makefile b/modules/libscpp/Makefile new file mode 100644 index 0000000..c0f4cac --- /dev/null +++ b/modules/libscpp/Makefile @@ -0,0 +1,48 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = libscpp +TARGET = $(NAME).so +SUBDIRS = test +USE_SO_VERSION = y + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(TOPDIR)/config.mk +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include -Iinclude +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/bkup/scpp.hpp b/modules/libscpp/bkup/scpp.hpp new file mode 100644 index 0000000..04184e2 --- /dev/null +++ b/modules/libscpp/bkup/scpp.hpp @@ -0,0 +1,13 @@ +/** + * @file scpp.h + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include + +#endif /* SCPP_H */ + diff --git a/modules/libscpp/bkup/scpp_assert.hpp b/modules/libscpp/bkup/scpp_assert.hpp new file mode 100644 index 0000000..094836e --- /dev/null +++ b/modules/libscpp/bkup/scpp_assert.hpp @@ -0,0 +1,29 @@ +/** + * @file scpp_assert.hpp + * @bried Assert モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include + +namespace scpp +{ + + +class AssertError : public std::exception +{ + public: + AssertError() noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string& msg) noexcept; + AssertError(const std::string% msg, +}; + + +} + + +#endif // SCPP_ASSERT_HPP diff --git a/modules/libscpp/bkup/scpp_exception.cpp b/modules/libscpp/bkup/scpp_exception.cpp new file mode 100644 index 0000000..5ed0c1c --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.cpp @@ -0,0 +1,13 @@ +/** + * @file scpp_exception.cpp + * @bried Exception モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + + +namespace scpp +{ +} + diff --git a/modules/libscpp/bkup/scpp_exception.hpp b/modules/libscpp/bkup/scpp_exception.hpp new file mode 100644 index 0000000..b37132f --- /dev/null +++ b/modules/libscpp/bkup/scpp_exception.hpp @@ -0,0 +1,65 @@ +/** + * @file scpp_exception.hpp + * @bried Exception モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + +/** + * 例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ +class Throwable: public std::exception +{ + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(const std::string& msg) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; +}; + + +/** + * 回復可能な例外クラス。 + */ +class Exception : public Throwable +{ + public: + Exception() noexcept; + Exception(const Throwable& t) noexcept; + Exception(const std::string& msg) noexcept; + virtual ~Exception() noexcept; +}; + + +/** + * 回復困難な例外クラス。 + */ +class Error : public Throwable +{ + public: + Error() noexcept; + Error(const Throwable& t) noexcept; + Error(const std::string& msg) noexcept; + virtual ~Error() noexcept; +}; + + +} + + +#endif // SCPP_EXCEPTION_HPP diff --git a/modules/libscpp/bkup/scpp_memory.cpp b/modules/libscpp/bkup/scpp_memory.cpp new file mode 100644 index 0000000..7213a9d --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.cpp @@ -0,0 +1,693 @@ +/** + * @file scpp_memory.cpp + * @bried メモリ管理モジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include +#include +#include +#include +#include + + +// 本来の malloc, free を利用するため、ENABLED_MEMORY_MANAGE を無効にする +#ifdef ENABLED_MEMORY_MANAGE +#undef ENABLED_MEMORY_MANAGE +#endif +#include + + + +using namespace scpp; +namespace +{ + int const PADDING = sizeof(int) * 2; + int const MARK_ALLOCATED = 0x12340000; + int const MARK_ALLOCATED_NEW = 0x12341111; + int const MARK_ALLOCATED_NEW_ARRAY = 0x12342222; + int const MARK_DELETED = 0xFEDCBA00; + + bool infoIsInitialized = false; + std::mutex memMtx; //< 管理メモリ操作用 Mutex + MemoryInfo infoHead; //< 管理メモリ先頭 + MemoryInfo infoTail; //< 管理メモリ末尾 + MemoryInfo infoError; //< エラー発生時用 + MemoryListener* listener = 0; //< 通知リスナ + + // プロトタイプ宣言 + void init(); + void add(MemoryInfo* entry); + void remove(MemoryInfo* entry); + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func); + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng); + + /** + * new ハンドラを取得します。 + * + * @return new ハンドラ + */ + std::new_handler getNewHandler() + { + std::new_handler p = std::set_new_handler(0); + std::set_new_handler(p); + return p; + } + + /** + * メモリ管理初期化. + */ + void init() + { + if (!infoIsInitialized) + { + infoIsInitialized = true; + infoHead.fileName = infoTail.fileName = 0; + infoHead.lineNumber = infoTail.lineNumber = 0; + infoHead.functionName = infoTail.functionName = 0; + infoHead.size = infoTail.size = 0; + infoHead._prev = infoHead._next = &infoTail; + infoTail._prev = infoTail._next = &infoHead; + infoHead._mark = infoTail._mark = MARK_DELETED; + + // エラー処理用 + infoError.fileName = 0; + infoError.lineNumber = 0; + infoError.functionName = 0; + infoError.size = 0; + infoError._prev = 0; + infoError._next = 0; + infoError._mark = MARK_DELETED; + } + } + + + /** + * メモリエントリを追加します. + * + * @param entry 追加するエントリ + */ + void add(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + init(); + entry->_next = &infoTail; + entry->_prev = infoTail._prev; + infoTail._prev->_next = entry; + infoTail._prev = entry; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyAlloc(*entry); + } + } + + + /** + * メモリエントリを削除します. + * + * @param entry 削除するエントリ + */ + void remove(MemoryInfo* entry) + { + std::lock_guard lock(memMtx); + entry->_prev->_next = entry->_next; + entry->_next->_prev = entry->_prev; + + if (listener) + { // ハンドラが設定されていれば実行する + listener->notifyFree(*entry); + } + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* allocate(std::size_t n, int mark, const char* file, int line, const char* func) + { + MemoryInfo* entry; + + // メモリ確保 [@see C++ Programming Language 3rd $14.4.5] + for (;;) + { + entry = static_cast (::malloc(n + sizeof(MemoryInfo) + PADDING)); + if (entry != 0) { break; } + + if (std::new_handler nhandler = getNewHandler()) + { + nhandler(); + } + else + { + return 0; + } + } + + void* ptr = (entry + 1); + + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = ptr; + + // エントリに追加 + add(entry); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param n 確保するメモリサイズ + * @param mark マーク + * @param file ファイル + * @param line 行番号 + * @param func 関数名 + */ + void* reallocate(void* ptr, std::size_t n, int mark, const char* file, int line, const char* func, bool isMng) + { + if (isMng) + { // 管理メモリの場合, いったん削除 + remove(static_cast(ptr)); + } + + MemoryInfo* entry = static_cast (::realloc(ptr, n + sizeof(MemoryInfo) + PADDING)); + if (entry == 0) + { + // メモリ確保失敗 -> 元の領域は開放されないので再管理する + add(static_cast(ptr)); + errno = ENOMEM; + if (listener) + { // エラーハンドラが登録されている + infoError.size = n; + infoError.fileName = file; + infoError.lineNumber = line; + infoError.functionName = func; + listener->notifyError(infoError, "can't realloc"); + } + return 0; + } + + if (!isMng) + { // 管理対象外メモリの場合 + // |<---- 新たな確保領域 ---->| + // +----------+---------------+ + // |元々の領域|追加分+管理領域| + // +----------+---------------+ + // ↓ + // +--------+----------+------+ + // |管理領域|元々の領域|追加分| + // +--------+----------+------+ + memmove((entry + 1), entry, n); + } + + // 管理領域に情報を書き込む + void* nptr = (entry + 1); + entry->fileName = file; + entry->lineNumber = line; + entry->functionName = func; + entry->size = n; + entry->_mark = mark; + entry->_data = nptr; + + // エントリに追加 + add(entry); + return nptr; + } + +} // namespace 無名 + + + +//////////////////////////////////////////////////////////////////////////////// +// +// 以下, new / delete のオーバライド +// + + +void* operator new(std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new[](std::size_t size) +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + if (p == 0) + { + throw std::bad_alloc(); + } + return p; +} + +void* operator new(std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + +void* operator new[](std::size_t size, const std::nothrow_t&) noexcept +{ + void* p = allocate(size, MARK_ALLOCATED_NEW_ARRAY, + MemoryManager::fileName, + MemoryManager::lineNumber, + MemoryManager::functionName); + return p; +} + + +void operator delete(void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } +} + +void operator delete(void* p, std::size_t) noexcept +{ + operator delete(p); +} + +void operator delete(void* p, const std::nothrow_t&) noexcept +{ + operator delete(p); +} + +void operator delete[](void* p) noexcept +{ + if (p == 0) + { // null ポインタの場合なにもしない + return; + } + + MemoryInfo* entry = (MemoryInfo*) p; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // malloc で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use free"); } + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + +} + +void operator delete[](void* p, std::size_t) noexcept +{ + operator delete[](p); +} + +void operator delete[](void* p, const std::nothrow_t&) noexcept +{ + operator delete[](p); +} + + +namespace scpp +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// デフォルトのメモリ確保/開放時に実行されるリスナ +// + +DefaultMemoryListener::DefaultMemoryListener() +{ + // NOP +} +DefaultMemoryListener::~DefaultMemoryListener() +{ + // NOP +} + +/** + * メモリが確保された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyAlloc(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリが開放された際に実行されるリスナ. + * デフォルトのリスナでは何もしません. + * + * @param info メモリ情報 + */ +void DefaultMemoryListener::notifyFree(const MemoryInfo&) +{ + // NOP +} + + +/** + * メモリの確保/開放でエラーが発生した際に実行されるリスナ. + * エラー内容をエラー出力します. + * + * @param info メモリ情報 + * @param msg メッセージ + */ +void DefaultMemoryListener::notifyError(const MemoryInfo& info, const std::string& msg) +{ + std::cerr << "MemoryError: " << msg << std::endl; + std::cerr << "\tat " << info.fileName << ":" << info.lineNumber << ":" << info.functionName + << " (size = " << info.size << ")" << std::endl; +} + + + +//////////////////////////////////////////////////////////////////////////////// +// +// メモリ管理 +// + +/** + * メモリ管理. + * メモリの確保, 開放を行います. + * リスナを登録することで, メモリ確保, 開放, エラー発生時の通知を + * 受信することができます. + * + * 以下のようにメモリを管理しています. + * @code + * + * |<----管理メモリ------------->| + * +--------+--------------------+ + * |管理領域|ユーザ使用メモリ領域| + * +--------+--------------------+ + * ↑ユーザにはこの位置を返す + * + * c++ なので std::list 等を使っても良いが, + * list のメモリ確保でエラーがでると本末転倒なので, + * メモリ確保時に管理領域をまとめて確保&管理する. + * @endcode + * + */ +namespace MemoryManager +{ + + thread_local const char* fileName = ""; // 名前一時保存用 + thread_local int lineNumber = 0; // 行番号一時保存用 + thread_local const char* functionName = ""; // 関数名一時保存用 + + /** + * メモリの確保,開放,エラー発生の通知を受信するリスナを登録します. + * + * @param l リスナ + */ + void setListener(MemoryListener* l) + { + listener = l; + } + + + /** + * 管理している全メモリエントリを引数に指定されたハンドラを実行します. + * デフォルトで用意しているハンドラ printMemoryInfo を使用できます. + * + * @param handler ハンドラ + */ + void entries(void (*handler)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + handler(*info); + info = info->_next; + } + } + + + /** + * 指定されたメソッドが true を返す管理メモリをクリア(削除)します. + * 本メソッド実行時, 管理しているメモリの情報を引数に + * 指定された関数が実行されます. + * + * [注意事項] + * 本メソッドでメモリはクリアしますが, デストラクタは呼び出されないので注意 + * + * 使用例) + * @code + * bool isCleanup(const scpp::MemoryInfo& info) + * { // 管理しているメモリ全てクリアする + * return true; + * } + * scpp::MemoryManager::cleanup(&isCleanup); + * @endcode + * + * @param isCleanup クリアするか否かを返す関数ポインタ + */ + void cleanup(bool (*isCleanup)(const MemoryInfo& info)) + { + if (!infoIsInitialized) { return; } + MemoryInfo* info = infoHead._next; + while (info != &infoTail) + { + bool ret = isCleanup(*info); + if (ret) + { // クリア対象 + MemoryInfo* tmpInfo; + tmpInfo = info; + info = info->_next; + remove(tmpInfo); + tmpInfo->size = 0; + tmpInfo->_mark = MARK_DELETED; + free(tmpInfo); + } + else + { + info = info->_next; + } + } + } + + + /** + * 指定されたメモリの情報を出力します. + * + * @param info メモリの情報 + */ + void printMemoryInfo(const MemoryInfo& info) + { + std::cout << "[MemoryInfo] " + << info.fileName << ":" + << info.lineNumber << ":" + << info.functionName << " (size = " + << info.size << ")" + << std::endl; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル名 + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* malloc(std::size_t size, const char* file, int line, const char* func) + { + void* ptr = allocate(size, MARK_ALLOCATED, file, line, func); + return ptr; + } + + + /** + * 指定されたサイズのメモリを確保します. + * + * @param nmemb 確保するメモリの要素数 + * @param size 確保するメモリサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func) + { + std::size_t n = nmemb * size; + void* ptr = allocate(n, MARK_ALLOCATED, file, line, func); + if (ptr) + { // callc なのでゼロクリアする + memset(ptr, 0x00, n); + } + return ptr; + } + + + /** + * ポインタが示すメモリブロックのサイズを変更します. + * + * @param ptr ポインタ + * @param size 確保するメモリのサイズ + * @param file 呼び出し元ソースファイル + * @param line 呼び出し元ソース行番号 + * @param func 呼び出し元関数名 + * @return 確保したメモリへのポインタ + */ + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func) + { + if (ptr == 0) + { // ptr が null の場合, malloc と等価 + ptr = malloc(size, file, line, func); + return ptr; + } + + if (size == 0) + { // size が 0 の場合, free と等価 + free(ptr); + return 0; + } + + // メモリ管理領域を取得 + MemoryInfo* entry = static_cast (ptr); + entry--; + void* nptr = 0; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 管理メモリ + nptr = reallocate(entry, size, MARK_ALLOCATED, file, line, func, true); + break; + case MARK_DELETED: // 削除済みメモリ + nptr = malloc(size, file, line, func); + break; + case MARK_ALLOCATED_NEW: // new で確保されたメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new : can't realloc"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "alloced new[] : can't realloc"); } + break; + default: // 管理対象外メモリ + nptr = reallocate(ptr, size, MARK_ALLOCATED, file, line, func, false); + } + + return nptr; + } + + + /** + * 指定されたメモリを開放します. + * + * @param ptr 開放するメモリへのポインタ + */ + void free(void* ptr) + { + MemoryInfo* entry; + if (ptr == 0) + { // null ポインタの場合なにもしない + return; + } + + // メモリ管理領域を取得 + entry = (MemoryInfo*) ptr; + entry--; + switch (entry->_mark) + { + case MARK_ALLOCATED: // 確保されたメモリ + remove(entry); + entry->_mark = MARK_DELETED; + entry->size = 0; + ::free(entry); + break; + case MARK_DELETED: // 削除済みのメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "deleted pointer"); } + break; + case MARK_ALLOCATED_NEW: // new で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete"); } + break; + case MARK_ALLOCATED_NEW_ARRAY: // new[] で確保したメモリ + errno = EINVAL; + if (listener) { listener->notifyError(*entry, "please use delete[]"); } + break; + default: // 管理外メモリ開放 + entry++; + ::free(entry); + break; + } + + } + + +} // namespace MemoryManager +} // namespace scpp + diff --git a/modules/libscpp/bkup/scpp_memory.hpp b/modules/libscpp/bkup/scpp_memory.hpp new file mode 100644 index 0000000..675ab75 --- /dev/null +++ b/modules/libscpp/bkup/scpp_memory.hpp @@ -0,0 +1,129 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * メモリの確保/解放/エラー発生時に呼び出されるリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHandler メソッドにて登録することで、 + * メモリの確保/解放/エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager で管理しているメモリに対してのみ有効です。 + * (MemoryManager::malloc, MemoryManager::calloc, MemoryManager::realloc) + * + * new, malloc, calloc などを対象とする場合、 + * ENABLED_MEMORY_MANAGE を定義してください。 + */ + class MemoryListener + { + public: + virtual void notifyAlloc(const MemoryInfo& info) = 0; + virtual void notifyFree(const MemoryInfo& info) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + virtual ~MemoryListener() = 0; + }; + + + /** + * メモリ確保/解放/エラー発生時のデフォルト通知インタフェースです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener&) = delete; + void operator=(const DefaultMemoryListener&) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info); + virtual void notifyFree(const MemoryInfo& info); + virtual void notifyError(const MemoryInfo& info, const std::string& msg); + }; + + + /** + * メモリ管理。 + * メモリの確保、解放を行います。 + * ハンドラを登録することで、メモリの確保/解放/エラー時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* fileName; + extern thread_local int lineNumber; + extern thread_local const char* functionName; + + void setListener(MemoryListener* handler); + void entries(void (*handler)(const MemoryInfo& info)); + void cleanup(bool (*isCleanup)(const MemoryInfo& info)); + void printMemoryInfo(const MemoryInfo& info); + void* malloc( std::size_t size, const char* file, int line, const char* func); + void* calloc(std::size_t nmemb, std::size_t size, const char* file, int line, const char* func); + void* realloc(void* ptr, std::size_t size, const char* file, int line, const char* func); + void free(void* ptr); + } + +} + + +#if (ENABLED_MEMORY_MANAGE) +#if IS_SUPPORTED_CPP20 +#define SCPP_NODISCARD [[nodiscard]] +#else +#define SCPP_NODISCARD +#endif + +SCPP_NODISCARD void* operator new(std::size_t size); +SCPP_NODISCARD void* operator new[](std::size_t size); + +SCPP_NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +SCPP_NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; + +// void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, std::size_t size) noexcept; + +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; + +// 実質メモリ管理しないので除外 +// SCPP_NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; + +#if IS_SUPPORTED_CPP17 +// 以下、未サポート +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// SCPP_NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// SCPP_NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t&) noexcept; +// +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// +#endif + +#define new \ + ((scpp::MemoryManager::fileName = __FILE__, \ + scpp::MemoryManager::lineNumber = __LINE__, \ + scpp::MemoryManager::functionName = __func__, \ + 0) && 0) ? 0 : new + +#define malloc(size) scpp::MemoryManager::malloc( size, __FILE__, __LINE__, __func__) +#define calloc(nmemb, size) scpp::MemoryManager::calloc(nmemb, size, __FILE__, __LINE__, __func__) +#define realloc(ptr, size) scpp::MemoryManager::realloc(ptr , size, __FILE__, __LINE__, __func__) +#define free(ptr) scpp::MemoryManager::free(ptr) + +#endif // (ENABLED_MEMORY_MANAGE) + +#endif // SCPP_MEMORY_HPP diff --git a/modules/libscpp/bkup/scpp_unittest.hpp b/modules/libscpp/bkup/scpp_unittest.hpp new file mode 100644 index 0000000..9b2b154 --- /dev/null +++ b/modules/libscpp/bkup/scpp_unittest.hpp @@ -0,0 +1,11 @@ +/** + * @file scpp_unitteset.hpp + * @bried 単体テストモジュールヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_UNITTEST_HPP +#define SCPP_UNITTEST_HPP + + +#endif // SCPP_UNITTEST_HPP diff --git a/modules/libscpp/include/scpp.hpp b/modules/libscpp/include/scpp.hpp new file mode 100644 index 0000000..00aaa98 --- /dev/null +++ b/modules/libscpp/include/scpp.hpp @@ -0,0 +1,15 @@ +/** + * @file scpp.hpp + * @bried 各ヘッダに取り込まれるヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_H +#define SCPP_H + +#include +#include +#include + +#endif // SCPP_H + diff --git a/modules/libscpp/include/scpp_assert.hpp b/modules/libscpp/include/scpp_assert.hpp new file mode 100644 index 0000000..76aeb30 --- /dev/null +++ b/modules/libscpp/include/scpp_assert.hpp @@ -0,0 +1,24 @@ +/** + * @file scpp_assert.hpp + * @bried アサーションモジュール + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * アサーション関数が失敗するとき、エラーメッセージを出力します。 + */ +#ifndef SCPP_ASSERT_HPP +#define SCPP_ASSERT_HPP + +#include +#include + +namespace scpp +{ + +/** + * アサーションに失敗した際に throw される Erro です。 + */ + + +#endif // SCPP_ASSERT_HPP + diff --git a/modules/libscpp/include/scpp_compiler.hpp b/modules/libscpp/include/scpp_compiler.hpp new file mode 100644 index 0000000..c56a6e2 --- /dev/null +++ b/modules/libscpp/include/scpp_compiler.hpp @@ -0,0 +1,42 @@ +/** + * @file scpp_compiler.hpp + * @bried C++言語バージョン判定マクロを定義したヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + * + * C++言語バージョンに応じてて次のマクロが定義されます。 + * - IS_SUPPORTED_CPP20 + * - IS_SUPPORTED_CPP17 + * - IS_SUPPORTED_CPP14 + * - IS_SUPPORTED_CPP11 + * + * C言語の場合、次の値は常に 0 となります。 + * - IS_SUPPORTED_C17 + * - IS_SUPPORTED_C11 + * - IS_SUPPORTED_C99 + * + */ +#ifndef SCPP_COMPILER_H +#define SCPP_COMPILER_H +#ifdef __cplusplus + + +#if (__cplusplus >= 201103L) +/* ----- C++11 以降の場合のみサポートする */ +#define IS_SUPPORTED_CPP20 (__cplusplus >= 202002L) +#define IS_SUPPORTED_CPP17 (__cplusplus >= 201703L) +#define IS_SUPPORTED_CPP14 (__cplusplus >= 201402L) +#define IS_SUPPORTED_CPP11 (__cplusplus >= 201103L) +#define IS_SUPPORTED_C17 (0) +#define IS_SUPPORTED_C11 (0) +#define IS_SUPPORTED_C99 (0) + +#else +/* ----- C++11 以前の場合はエラーとする */ +#error "unsupported c++ version, please use c++11 or later" + +#endif /* (__cplusplus >= 201103L) */ + + +#endif /* __cplusplus */ +#endif /* SCPP_COMPILER_H */ diff --git a/modules/libscpp/include/scpp_exception.hpp b/modules/libscpp/include/scpp_exception.hpp new file mode 100644 index 0000000..70df85f --- /dev/null +++ b/modules/libscpp/include/scpp_exception.hpp @@ -0,0 +1,77 @@ +/** + * @file scpp_exception.hpp + * @bried 例外クラス用ヘッダーファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_EXCEPTION_HPP +#define SCPP_EXCEPTION_HPP + +#include +#include + +#include + +namespace scpp +{ + + + /** + * 本ライブラリの例外基底クラス。 + * libscpp で扱う例外は、本クラスを継承します。 + */ + class Throwable : public std::exception + { + public: + Throwable() noexcept; + Throwable(const Throwable& t) noexcept; + Throwable(Throwable&& t) noexcept; + Throwable(const std::string& msg) noexcept; + Throwable& operator=(const Throwable& t) noexcept; + Throwable& operator=(Throwable&& t) noexcept; + virtual ~Throwable() noexcept; + virtual const char* what() const noexcept; + protected: + std::string message; + }; + + + /** + * 本ライブラリの Exception クラス。 + * 本ライブラリにて発生したエラーのうち、回復可能なエラーは、 + * 本クラスを継承した Exception クラスを throw します。 + */ + class Exception : public Throwable + { + public: + Exception() noexcept; + Exception(const Exception& e) noexcept; + Exception(Exception&& e) noexcept; + Exception(const std::string& msg) noexcept; + Exception& operator=(const Exception& t) noexcept; + Exception& operator=(Exception&& t) noexcept; + virtual ~Exception() noexcept; + }; + + + /** + * 本ライブラリの Error クラス。 + * 本ライブラリにて発生したエラーのうち、回復困難なエラーは、 + * 本クラスを継承した Error クラスを throw します。 + */ + class Error : public Throwable + { + public: + Error() noexcept; + Error(const Error& t) noexcept; + Error(Error&& t) noexcept; + Error(const std::string& msg) noexcept; + Error& operator=(const Error& t) noexcept; + Error& operator=(Error&& t) noexcept; + virtual ~Error() noexcept; + }; + +} // namespace scpp + +#endif // SCPP_EXCEPTION_HPP + diff --git a/modules/libscpp/include/scpp_memory.hpp b/modules/libscpp/include/scpp_memory.hpp new file mode 100644 index 0000000..7a23506 --- /dev/null +++ b/modules/libscpp/include/scpp_memory.hpp @@ -0,0 +1,135 @@ +/** + * @file scpp_memory.hpp + * @bried メモリ管理モジュールヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_MEMORY_HPP +#define SCPP_MEMORY_HPP + +#include +#include +#include + + +#include + +namespace scpp +{ + +#include + + typedef sc_memory MemoryInfo; + + + /** + * メモリが確保、解放、あるいはメモリ確保/解放時にエラーが発生した際のリスナインタフェース。 + * ユーザーは、本リスナを実装し、MemoryManager::setHander メソッドにて登録することで、 + * メモリの確保、解放、エラー発生時の通知を受信することが可能です。 + * + * 本リスナは、MemoryManager にて管理しているメモリに対してのみ有効です。 + */ + class MemoryListener + { + public: + MemoryListener(); + MemoryListener(const MemoryListener& l) = delete; + MemoryListener& operator=(const MemoryListener& l) = delete; + virtual ~MemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyFree( const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + }; + + + /** + * メモリ確保、解放、メモリ確保/解放時にエラーが発生した際のデフォルトのリスナです。 + */ + class DefaultMemoryListener : public MemoryListener + { + public: + DefaultMemoryListener(); + DefaultMemoryListener(const DefaultMemoryListener& l) = delete; + DefaultMemoryListener& operator=(const DefaultMemoryListener& l) = delete; + virtual ~DefaultMemoryListener(); + virtual void notifyAlloc(const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyFree( const MemoryInfo& info, const std::string& msg) = 0; + virtual void notifyError(const MemoryInfo& info, const std::string& msg) = 0; + }; + + + /** + * メモリ管理。 + * メモリ確保、解放を行います。 + * ハンドラを登録することで、メモリ確保、解放、エラー発生時の通知を受信することができます。 + */ + namespace MemoryManager + { + extern thread_local const char* file; + extern thread_local int line; + extern thread_local const char* func; + + void setListener(MemoryListener& handler); + void entries(void (*handler)(const MemoryInfo& info)); + void freeif(bool (*handler)(const MemoryInfo& info)); + } + + +#if defined(SC_MEMORY_MANAGE) || defined(SCPP_MEMORY_MANAGE) + +#if (IS_SUPPORTED_CPP20) +// C++20 +#define NODISCARD [[nodiscard]] +#else +// C++20 以外 +#define NODISCARD +#endif + +// ----- C++11 ----- +NODISCARD void* operator new(std::size_t size); +NODISCARD void* operator new[](std::size_t size); +NODISCARD void* operator new(std::size_t size, const std::nothrow_t& t) noexcept; +NODISCARD void* operator new[](std::size_t size, const std::nothrow_t& t) noexcept; +void operator delete(void* ptr) noexcept; +void operator delete(void* ptr, const std::nothrow_t& t) noexcept; +void operator delete[](void* ptr, const std::nothrow_t& t) noexcept; +// 以下、実質メモリ管理しないため除外 +// NODISCARD void* operator new(std::size_t size, void* ptr) noexcept; +// NODISCARD void* operator new[](std::size_t size, void* ptr) noexcept; +// void operator delete(void* ptr, void*) noexcept; + +#if IS_SUPPORTED_CPP14 +// ----- C++14 ----- +void operator delete(void* ptr, std::size_t size) noexcept; +#endif + + +#if IS_SUPPORTED_CPP17 +// ----- C++17 ----- +// 現状未サポート [実装 +// NODISCARD void* operator new(std::size_t size, std::align_val_t alignment); +// NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment); +// NODISCARD void* operator new(std::size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// NODISCARD void* operator new[](std::size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +// void operator delete(void* ptr, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment) noexcept; +// void operator delete(void* ptr, size_t size, std::align_val_t alignment, const std::nothrow_t& t) noexcept; +#endif // IS_SUPPORTED_CPP17 + +// ----- C++20 ----- +// C++11, C++17 の new に [[nodiscard]] が付与されている +// => マクロで対応済み + +// new の差し替え。 +// 先頭 +#define new \ + ((scpp::MemoryManager::file = __FILE__, \ + scpp::MemoryManager::line = __LINE__, \ + scpp::MemoryManager::func = __func__, \ + 0) && 0) ? 0 : new + +#endif // defined(SC_MEMORY_MANAGE) || defined(SCPP_MEMORY_MANAGE) + +} // namespace scpp + +#endif // SCPP_MEMORY_HPP diff --git a/modules/libscpp/include/scpp_unittest.hpp b/modules/libscpp/include/scpp_unittest.hpp new file mode 100644 index 0000000..038f7ab --- /dev/null +++ b/modules/libscpp/include/scpp_unittest.hpp @@ -0,0 +1,15 @@ +/** + * @file scpp_unittest.hpp + * @bried 簡易単体テスト用ヘッダファイル + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#ifndef SCPP_UNITTEST_HPP +#define SCPP_UNITTEST_HPP + + +#include + + +#endif // SCPP_UNITTEST_HPP + diff --git a/modules/libscpp/src/.scpp_exception.cpp.swp b/modules/libscpp/src/.scpp_exception.cpp.swp new file mode 100644 index 0000000..fa01bc2 --- /dev/null +++ b/modules/libscpp/src/.scpp_exception.cpp.swp Binary files differ diff --git a/modules/libscpp/src/scpp_exception.cpp b/modules/libscpp/src/scpp_exception.cpp new file mode 100644 index 0000000..862f834 --- /dev/null +++ b/modules/libscpp/src/scpp_exception.cpp @@ -0,0 +1,272 @@ +/** + * @file scpp_exception.cpp + * @bried Java ライクな Exception を扱うモジュール。 + * @author Nomura Kei + * @copyright 2003 - 2022 Nomura Kei + */ +#include + +#include +#include + +#include + + +namespace scpp +{ + + //////////////////////////////////////////////////////////////////////////// + // + // Throwable + // + + /** + * 最後に発生した errno に対応するメッセージを持つ Throwable を構築します。 + * エラーメッセージを取得できない場合、空文字がエラーメッセージに設定されます。 + */ + Throwable::Throwable() noexcept : message(sc_get_errmsg(NULL, 0, sc_get_errno())) + { + // NOP + } + + + /** + * コピーコンストラクタ。 + * + * @param t コピー元 + */ + Throwable::Throwable(const Throwable& t) noexcept : message(t.message) + { + // NOP + } + + + /** + * ムーブコンストラクタ。 + * + * @param t ムーブ元 + */ + Throwable::Throwable(Throwable&& t) noexcept : message(std::move(t.message)) + { + // NOP + } + + + /** + * 指定されたメッセージを持つ Throwable を構築します。 + * + * @param msg メッセージ + */ + Throwable::Throwable(const std::string& msg) noexcept : message(msg) + { + // NOP + } + + + /** + * コピー代入演算子 + * + * @param t 代入元 + */ + Throwable& Throwable::operator=(const Throwable& t) noexcept + { + this->message = t.message; + return (*this); + } + + + /** + * ムーブ代入演算子 + * + * @param t 代入元 + */ + Throwable& Throwable::operator=(Throwable&& t) noexcept + { + this->message = std::move(t.message); + return (*this); + } + + + /** + * デストラクタ。 + */ + Throwable::~Throwable() noexcept + { + // NOP + } + + + /** + * エラーメッセージを返します。 + * + * @return エラーメッセージ + */ + const char* Throwable::what() const noexcept + { + return message.c_str(); + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // Exception + // + + /** + * Exception を構築します。 + */ + Exception::Exception() noexcept : Throwable() + { + // NOP + } + + + /** + * コピーコンストラクタ。 + * + * @param t コピー元 + */ + Exception::Exception(const Exception& t) noexcept : Throwable(t) + { + // NOP + } + + + /** + * ムーブコンストラクタ。 + * + * @param t ムーブ元 + */ + Exception::Exception(Exception&& t) noexcept : Throwable(t) + { + // NOP + } + + + /** + * 指定されたメッセージを持つ Exception を構築します。 + * + * @param msg メッセージ + */ + Exception::Exception(const std::string& msg) noexcept : Throwable(msg) + { + // NOP + } + + + /** + * コピー代入演算子 + * + * @param t 代入元 + */ + Exception& Exception::operator=(const Exception& t) noexcept + { + Throwable::operator=(t); + return (*this); + } + + + /** + * ムーブ代入演算子 + * + * @param t 代入元 + */ + Exception& Exception::operator=(Exception&& t) noexcept + { + Throwable::operator=(t); + return (*this); + } + + + /** + * デストラクタ。 + */ + Exception::~Exception() noexcept + { + // NOP + } + + + + //////////////////////////////////////////////////////////////////////////// + // + // Error + // + + /** + * Error を構築します。 + */ + Error::Error() noexcept : Throwable() + { + // NOP + } + + + /** + * コピーコンストラクタ。 + * + * @param t コピー元 + */ + Error::Error(const Error& t) noexcept : Throwable(t) + { + // NOP + } + + + /** + * ムーブコンストラクタ。 + * + * @param t ムーブ元 + */ + Error::Error(Error&& t) noexcept : Throwable(t) + { + // NOP + } + + + /** + * 指定されたメッセージを持つ Error を構築します。 + * + * @param msg メッセージ + */ + Error::Error(const std::string& msg) noexcept : Throwable(msg) + { + // NOP + } + + + /** + * コピー代入演算子 + * + * @param t 代入元 + */ + Error& Error::operator=(const Error& t) noexcept + { + Throwable::operator=(t); + return (*this); + } + + + /** + * ムーブ代入演算子 + * + * @param t 代入元 + */ + Error& Error::operator=(Error&& t) noexcept + { + Throwable::operator=(t); + return (*this); + } + + + /** + * デストラクタ。 + */ + Error::~Error() noexcept + { + // NOP + } + +} + diff --git a/modules/libscpp/test/Makefile b/modules/libscpp/test/Makefile new file mode 100644 index 0000000..dc6af03 --- /dev/null +++ b/modules/libscpp/test/Makefile @@ -0,0 +1,47 @@ +# ============================================================================== +# Makefile +# ============================================================================== +# +# TOPDIR : トップディレクトリ +# RULEDIR : Meke のルール一式が格納されているディレクトリ +# NAME : モジュール名 (拡張子を含めないこと) +# TARGET : モジュールファイル名 (拡張子を含めること) +# SUBDIR : サブディレクトリ (処理したい順に空白区切りで記述すること) +# +TOPDIR ?= ../../.. +RULEDIR ?= $(TOPDIR)/mk +NAME = ut.exe +TARGET = $(NAME) +SUBDIRS = +USE_SO_VERSION = + +# ------------------------------------------------------------------------------ +# *-cmd.mk : コマンド +# *-conf.mk : 設定 +# *-auto.mk : 自動設定 +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-cmd.mk +include $(RULEDIR)/*-conf.mk +include $(RULEDIR)/*-auto.mk +# ------------------------------------------------------------------------------ +# +# 以下、オプションを適宜変更してください。 +# + +INCLUDES += -I$(TOPDIR)/include +CFLAGS += +CXXFLAGS += +LDFLAGS += +LIBS += -L$(TOPDIR)/lib + +CLEAN_FILES += +CLEAN_DIRS += + +.DEFAULT_GOAL := all + +# ------------------------------------------------------------------------------ +# *-rule : ルール +# ------------------------------------------------------------------------------ +include $(RULEDIR)/*-rule.mk +# ------------------------------------------------------------------------------ + diff --git a/modules/libscpp/test/src/test.c b/modules/libscpp/test/src/test.c new file mode 100644 index 0000000..4265469 --- /dev/null +++ b/modules/libscpp/test/src/test.c @@ -0,0 +1,15 @@ +#include + +#include "calc.h" + + +int main(void) +{ + int a = 5; + int b = 100; + int c = add(a, b); + printf("%d\n", c); + return 0; +} + +