From b41576197133c1211d6ec353faf93f505f573b8a Mon Sep 17 00:00:00 2001 From: Owen Shepherd Date: Thu, 2 Aug 2012 21:48:01 +0100 Subject: [PATCH] * Change the style of inclusion of the internal/ headers. Modern preprocessors all detect the header guards and know not to include anyhow. The old style may have actually been counterproductive * Make the built library be standard independent (i.e. the library build is independent of _PDCLIB_C_VERSION/__STDC_VERSION__/_PDCLIB_CXX_VERSION /__cplusplus. * from C11. A bit off of the track of C99 support (which is still a higher priority goal), but solid implementation of many C99 functions on many real platforms will need proper thread support. support to come. This is a stub implementation. * Move malloc/free/realloc etc to opt/malloc-solar, in preparation for support of other memory allocators. On the cards are at least ptmalloc3 (BSD) and dlmalloc (public domain) as options. * New build system (See CoreMakefile.mk). Not ready yet; but its coming. This doesn't change the project dependencies - you still only need GNU make. This is a large bundle of changes - most of them are as a result of implementing PDClib into my system, so they're mostly "changes I was doing" that have got wrapped up together. Hopefully, now that things are together, future changesets should be better factored. Special thanks go to Martin "Solar" Baute for the work he has put in on this code over many years. --- CoreMakefile.mk | 35 +++ Readme.Legacy.txt | 217 ++++++++++++++ Readme.txt | 379 +++++++++++-------------- functions/_PDCLIB/assert.c | 11 +- functions/_PDCLIB/atomax.c | 1 - functions/_PDCLIB/digits.c | 3 - functions/_PDCLIB/errno.c | 1 - functions/_PDCLIB/prepread.c | 1 - functions/_PDCLIB/stdarg.c | 2 + functions/_PDCLIB/strtox_main.c | 1 - functions/stdio/fgets.c | 1 - functions/stdio/fwrite.c | 8 +- functions/stdio/gets.c | 2 - functions/string/strdup.c | 46 +++ includes/assert.h | 48 ++-- includes/ctype.h | 6 +- includes/errno.h | 6 +- includes/inttypes.h | 3 +- includes/iso646.h | 2 + includes/limits.h | 4 - includes/locale.h | 6 +- includes/stdarg.h | 7 +- includes/stdbool.h | 3 + includes/stddef.h | 12 +- includes/stdint.h | 4 - includes/stdio.h | 8 +- includes/stdlib.h | 12 +- includes/stdnoreturn.h | 16 ++ includes/string.h | 10 +- includes/threads.h | 98 +++++++ includes/time.h | 31 ++ internals/_PDCLIB_aux.h | 96 ++++++- internals/_PDCLIB_glue.h | 10 +- internals/_PDCLIB_int.h | 41 ++- opt/malloc-solar/calloc.c | 49 ++++ opt/malloc-solar/free.c | 55 ++++ opt/malloc-solar/malloc.c | 425 ++++++++++++++++++++++++++++ opt/malloc-solar/realloc.c | 58 ++++ opt/nothread/_PDCLIB_threadconfig.h | 24 ++ opt/nothread/call_once.c | 9 + opt/nothread/cnd_init.c | 7 + opt/nothread/cnd_signal.c | 6 + opt/nothread/cnd_wait.c | 6 + opt/nothread/config.mk | 0 opt/nothread/mtx_destroy.c | 4 + opt/nothread/mtx_init.c | 7 + opt/nothread/mtx_lock.c | 10 + opt/nothread/mtx_timedlock.c | 6 + opt/nothread/mtx_trylock.c | 11 + opt/nothread/mtx_unlock.c | 9 + opt/nothread/thrd_yield.c | 6 + opt/nothread/tss_create.c | 8 + opt/nothread/tss_delete.c | 6 + opt/nothread/tss_get.c | 6 + opt/nothread/tss_set.c | 7 + 55 files changed, 1511 insertions(+), 339 deletions(-) create mode 100644 CoreMakefile.mk create mode 100644 Readme.Legacy.txt create mode 100644 functions/string/strdup.c create mode 100644 includes/stdnoreturn.h create mode 100644 includes/threads.h create mode 100644 includes/time.h create mode 100644 opt/malloc-solar/calloc.c create mode 100644 opt/malloc-solar/free.c create mode 100644 opt/malloc-solar/malloc.c create mode 100644 opt/malloc-solar/realloc.c create mode 100644 opt/nothread/_PDCLIB_threadconfig.h create mode 100644 opt/nothread/call_once.c create mode 100644 opt/nothread/cnd_init.c create mode 100644 opt/nothread/cnd_signal.c create mode 100644 opt/nothread/cnd_wait.c create mode 100644 opt/nothread/config.mk create mode 100644 opt/nothread/mtx_destroy.c create mode 100644 opt/nothread/mtx_init.c create mode 100644 opt/nothread/mtx_lock.c create mode 100644 opt/nothread/mtx_timedlock.c create mode 100644 opt/nothread/mtx_trylock.c create mode 100644 opt/nothread/mtx_unlock.c create mode 100644 opt/nothread/thrd_yield.c create mode 100644 opt/nothread/tss_create.c create mode 100644 opt/nothread/tss_delete.c create mode 100644 opt/nothread/tss_get.c create mode 100644 opt/nothread/tss_set.c diff --git a/CoreMakefile.mk b/CoreMakefile.mk new file mode 100644 index 0000000..ac7d495 --- /dev/null +++ b/CoreMakefile.mk @@ -0,0 +1,35 @@ +TARGETS = pdclib + +ifndef PDCLIB_PLATFORM_EXT +endif + +ifndef PDCLIB_MALLOC + $(error malloc to use unspecified. Set PDCLIB_MALLOC.) +endif + +ifeq ($(PDCLIB_MALLOC),solar) + pdclib_SOURCEDIRS += opt/malloc-solar +else +ifeq ($(PDCLIB_MALLOC),ptmalloc3) + pdclib_SOURCEDIRS += opt/ptmalloc3 +else + $(error Bad malloc specified. Supported: solar, ptmalloc3) +endif +endif + +# No: -Wcast-align; spurious for uses of char* to do pointer arithmetic +# No: -Winline; generates spirous errors on -Os builds +WARNINGS := -Wall -Wextra -pedantic -Wno-unused-parameter -Wshadow -Wpointer-arith -Wwrite-strings -Wmissing-prototypes -Wmissing-declarations -Wredundant-decls -Wnested-externs -Wno-long-long -Wuninitialized -Wstrict-prototypes + +pdclib_COMFLAGS += -ffreestanding $(WARNINGS) +pdclib_CFLAGS += -std=c11 +pdclib_SOURCEDIRS += functions/_PDCLIB functions/ctype functions/inttypes \ + functions/locale functions/stdio functions/stdlib \ + functions/string/ +pdclib_OUT_TYPE += archive +pdclib_INCLUDE_DIRS += $(pdclib_SOURCE_DIR)/includes $(pdclib_SOURCE_DIR)/internals + +ifdef PDCLIB_OPT_NOTHREAD + pdclib_SOURCEDIRS += opt/nothread + pdclib_INCLUDE_DIRS += $(pdclib_SOURCE_DIR)/opt/nothread +endif \ No newline at end of file diff --git a/Readme.Legacy.txt b/Readme.Legacy.txt new file mode 100644 index 0000000..0628fc6 --- /dev/null +++ b/Readme.Legacy.txt @@ -0,0 +1,217 @@ +$Id$ + +PDCLib - Public Domain C Library +================================ + +License +------- + +Permission is granted to use, modify, and / or redistribute at will. + +This includes removing authorship notices, re-use of code parts in +other software (with or without giving credit), and / or creating a +commercial product based on it. + +This permission is not revocable by the author. + +This software is provided as-is. Use it at your own risk. There is +no warranty whatsoever, neither expressed nor implied, and by using +this software you accept that the author(s) shall not be held liable +for any loss of data, loss of service, or other damages, be they +incidental or consequential. Your only option other than accepting +this is not to use the software at all. + +A case for Public Domain +------------------------ + +There was a time when you could just post a piece of code to usenet +and say, "I give it away for free; perhaps it's useful for you." + +Then came the lawyers. + +There are building blocks in software engineering that are so basic +that everyone should have free access to them without having to +employ a complete legal department for advice. They should be FREE. +Available for free, free of licensing implications, free of attached +propaganda, free of everything but their useful self. + +Today, even the term "free" has to be defined by several paragraphs +of legal blah-blah. + +Sick and tired of it, the author brought you this piece of software +under a "license" that should not be neccessary in the first place: +"Free" should have been enough. + +Unfortunately, German law does not even *allow* to declare a work to +be "in the Public Domain", so the "free for all" license I intended +had to be made expressively. + +What is it +---------- + +This is a C Standard Library. Nothing more, nothing less. No POSIX +or other extensions, just what's defined in ISO/IEC 9899. + +(Well, this is what it will be when the 1.0 release comes out. See +the "Development Status" section to see what's implemented so far.) + +Internals +--------- + +As a namespace convention, everything (files, typedefs, functions, +macros) not defined in ISO/IEC 9899 is prefixed with _PDCLIB. +The standard defines any identifiers starting with '_' and a capital +letter as reserved for the implementation, and since the chances of +your compiler using an identifier in the _PDCLIB range are slim, +any strictly conforming application should work with this library. + +PDCLib consists of several parts: + +1) standard headers; +2) implementation files for standard functions; +3) internal header files keeping complex stuff out of the standard + headers; +4) the central, platform-specific file _PDCLIB_config.h; +5) platform-specific implementation files; +6) platform-specific, optimized "overlay" implementations (optional). + +The standard headers (in ./includes/) only contain what they are +defined to contain. Where additional logic or macro magic is +necessary, that is deferred to the internal files. This has been done +so that the headers are actually educational as to what they provide +(as opposed to how the library does it). + +Note that there *might* be some feature to remove this additional +level of indirection for a production release, to ease the workload +put on the preprocessor. + +There is a seperate implementation file (in ./function/{header}/) for +every function defined by the standard, named {function}.c. Not only +does this avoid linking in huge amounts of unused code when you use +but a single function, it also allows the optimization overlay to work +(see below). + +(The directory ./functions/_PDCLIB/ contains internal and helper +functions that are not part of the standard.) + +Then there are internal header files (in ./internal/), which contain +all the "black magic" and "code fu" that was kept out of the standard +headers. You should not have to touch them if you want to adapt PDCLib +to a new platform. Note that, if you *do* have to touch them, I would +consider it a serious design flaw, and would be happy to fix it in the +next PDCLib release. Any adaption work should be covered by the steps +detailed below. + +For adapting PDCLib to a new platform (the trinity of CPU, operating +system, and compiler), make a copy of ./platform/example/ named +./platform/{your_platform}/, and modify the files of your copy to suit +the constraints of your platform. When you are done, copy the contents +of your platform directory over the source directory structure +of PDCLib (or link them into the appropriate places). That should be +all that is actually required to make PDCLib work for your platform. + +Of course, your platform might provide more efficient replacements +for the generic implementations offered by PDCLib. The math functions +are an especially "juicy" target for optimization - while PDCLib does +provide generic implementations for each of them, there are usually +FPU opcodes that do the same job, only orders of magnitude faster. For +this, you might want to create an "optimization overlay" for PDCLib. + +Optimization Overlay +-------------------- + +The basic idea of PDCLib is to provide a generic implementation that +is useable even on platforms I have never heard of - for example, the +OS and/or compiler *you* just wrote and now need a C library for. That +is actually what PDCLib was written for: To provide a C library for +compiler and OS builders that do not want the usual baggage of POSIX +and GNU extensions, licensing considerations etc. etc. + +Thus, PDCLib provides generic implementations. They do work, and do +so correctly, but they are not very efficient when compared to hand- +crafted assembler or compiler build-ins. So I wanted to provide a +means to modify PDCLib to run more efficiently on a given platform, +without cluttering the main branch with tons of #ifdef statements and +"featureset #defines" that grow stale quickly. + +The solution is the "optimization overlay". Every function has its +own implementation file, which makes it possible to replace them +piecemeal by copying a platform-specific overlay over the main PDCLib +branch to create a PDCLib adapted / optimized for the platform in +question. That overlay could be part of the PDCLib source tree (for +established platforms where maintainers won't bother with PDCLib), or +part of that platform's source tree (for under-development platforms +PDCLib maintainers won't bother with). + +So, to use PDCLib on your given platform, you unpack PDCLib (as you +obviously have done already since you are reading this), and copy +the overlay for your platform over the PDCLib source tree structure. + +Development Status +------------------ + +v0.1 - 2004-12-12 +Freestanding-only C99 implementation without any overlay, and missing +the INTN_C() / UINTN_C() macros. still has the enquire.c +values hardcoded into it; not sure whether to include enquire.c in the +package, to leave to the overlay, or devise some parameterized +macro magic as for / . Not thoroughly tested, but +I had to make the 0.1 release sometime so why not now. + +v0.2 - 2005-01-12 +Adds implementations for (excluding strerror()), INTN_C() / +UINTN_C() macros, and some improvements in the internal headers. +Test drivers still missing, but added warnings about that. + +v0.3 - 2005-11-21 +Adds test drivers, fixes some bugs in . + +v0.4 - 2005-02-06 +Implementations for parts of . Still missing are the floating +point conversions, and the wide-/multibyte-character functions. + +v0.4.1 - 2006-11-16 +With v0.5 () taking longer than expected, v0.4.1 was set up as +a backport of bugfixes in the current development code. +- #1 realloc( NULL, size ) fails (fixed) +- #2 stdlib.h - insufficient documentation (fixed) +- #4 Misspelled name in credits (fixed) +- #5 malloc() splits off too-small nodes (fixed) +- #6 qsort() stack overflow (fixed) +- #7 malloc() bug in list handling (fixed) +- #8 strncmp() does not terminate at '\0' (fixed) +- #9 stdint.h dysfunctional (fixed) +- #10 NULL redefinition warnings (fixed) + +v0.5 - 2010-12-22 +Implementations for , , most parts of , +and strerror() from . +Still no locale / wide-char support. Enabled all GCC compiler warnings I +could find, and fixed everything that threw a warning. (You see this, +maintainers of Open Source software? No warnings whatsoever. Stop telling +me it cannot be done.) Fixed all known bugs in the v0.4 release. + + +A WORD ON THE v0.5 RELEASE +========================== + +The v0.5 release is not well-tested. There are several things in it done +in a way that I would never label "release quality". Some things are not +even in the *structure* I would like them to be. An example for this is +the current handling of errno values: It needlessly introduces dependency +on PDCLib (because I use non-standard values), and the values are placed +in the wrong header (_PDCLIB_int.h instead of _PDCLIB_glue.h where they +would be more appropriate). + +But at some point during the development toward the v0.5 release, I found +that my current PDCLib work schedule simply does not allow me to wait +until every piece of is as I would like it to be. It would +probably take another year or two, and my patience is UP. + +I want this released, and I want to think about something else but + for some time. + +So, expect significant change to how stdio is done in upcoming releases. +Everything *WILL* be stable by the time v1.0 comes around, but until then +you will have to accept that I can only deliver "hobby quality" for now. + diff --git a/Readme.txt b/Readme.txt index 0628fc6..77762e5 100644 --- a/Readme.txt +++ b/Readme.txt @@ -1,217 +1,162 @@ -$Id$ - -PDCLib - Public Domain C Library -================================ - -License -------- - -Permission is granted to use, modify, and / or redistribute at will. - -This includes removing authorship notices, re-use of code parts in -other software (with or without giving credit), and / or creating a -commercial product based on it. - -This permission is not revocable by the author. - -This software is provided as-is. Use it at your own risk. There is -no warranty whatsoever, neither expressed nor implied, and by using -this software you accept that the author(s) shall not be held liable -for any loss of data, loss of service, or other damages, be they -incidental or consequential. Your only option other than accepting -this is not to use the software at all. - -A case for Public Domain ------------------------- - -There was a time when you could just post a piece of code to usenet -and say, "I give it away for free; perhaps it's useful for you." - -Then came the lawyers. - -There are building blocks in software engineering that are so basic -that everyone should have free access to them without having to -employ a complete legal department for advice. They should be FREE. -Available for free, free of licensing implications, free of attached -propaganda, free of everything but their useful self. - -Today, even the term "free" has to be defined by several paragraphs -of legal blah-blah. - -Sick and tired of it, the author brought you this piece of software -under a "license" that should not be neccessary in the first place: -"Free" should have been enough. - -Unfortunately, German law does not even *allow* to declare a work to -be "in the Public Domain", so the "free for all" license I intended -had to be made expressively. - -What is it ----------- - -This is a C Standard Library. Nothing more, nothing less. No POSIX -or other extensions, just what's defined in ISO/IEC 9899. - -(Well, this is what it will be when the 1.0 release comes out. See -the "Development Status" section to see what's implemented so far.) - -Internals ---------- - -As a namespace convention, everything (files, typedefs, functions, -macros) not defined in ISO/IEC 9899 is prefixed with _PDCLIB. -The standard defines any identifiers starting with '_' and a capital -letter as reserved for the implementation, and since the chances of -your compiler using an identifier in the _PDCLIB range are slim, -any strictly conforming application should work with this library. - -PDCLib consists of several parts: - -1) standard headers; -2) implementation files for standard functions; -3) internal header files keeping complex stuff out of the standard - headers; -4) the central, platform-specific file _PDCLIB_config.h; -5) platform-specific implementation files; -6) platform-specific, optimized "overlay" implementations (optional). - -The standard headers (in ./includes/) only contain what they are -defined to contain. Where additional logic or macro magic is -necessary, that is deferred to the internal files. This has been done -so that the headers are actually educational as to what they provide -(as opposed to how the library does it). - -Note that there *might* be some feature to remove this additional -level of indirection for a production release, to ease the workload -put on the preprocessor. - -There is a seperate implementation file (in ./function/{header}/) for -every function defined by the standard, named {function}.c. Not only -does this avoid linking in huge amounts of unused code when you use -but a single function, it also allows the optimization overlay to work -(see below). - -(The directory ./functions/_PDCLIB/ contains internal and helper -functions that are not part of the standard.) - -Then there are internal header files (in ./internal/), which contain -all the "black magic" and "code fu" that was kept out of the standard -headers. You should not have to touch them if you want to adapt PDCLib -to a new platform. Note that, if you *do* have to touch them, I would -consider it a serious design flaw, and would be happy to fix it in the -next PDCLib release. Any adaption work should be covered by the steps -detailed below. - -For adapting PDCLib to a new platform (the trinity of CPU, operating -system, and compiler), make a copy of ./platform/example/ named -./platform/{your_platform}/, and modify the files of your copy to suit -the constraints of your platform. When you are done, copy the contents -of your platform directory over the source directory structure -of PDCLib (or link them into the appropriate places). That should be -all that is actually required to make PDCLib work for your platform. - -Of course, your platform might provide more efficient replacements -for the generic implementations offered by PDCLib. The math functions -are an especially "juicy" target for optimization - while PDCLib does -provide generic implementations for each of them, there are usually -FPU opcodes that do the same job, only orders of magnitude faster. For -this, you might want to create an "optimization overlay" for PDCLib. - -Optimization Overlay --------------------- - -The basic idea of PDCLib is to provide a generic implementation that -is useable even on platforms I have never heard of - for example, the -OS and/or compiler *you* just wrote and now need a C library for. That -is actually what PDCLib was written for: To provide a C library for -compiler and OS builders that do not want the usual baggage of POSIX -and GNU extensions, licensing considerations etc. etc. - -Thus, PDCLib provides generic implementations. They do work, and do -so correctly, but they are not very efficient when compared to hand- -crafted assembler or compiler build-ins. So I wanted to provide a -means to modify PDCLib to run more efficiently on a given platform, -without cluttering the main branch with tons of #ifdef statements and -"featureset #defines" that grow stale quickly. - -The solution is the "optimization overlay". Every function has its -own implementation file, which makes it possible to replace them -piecemeal by copying a platform-specific overlay over the main PDCLib -branch to create a PDCLib adapted / optimized for the platform in -question. That overlay could be part of the PDCLib source tree (for -established platforms where maintainers won't bother with PDCLib), or -part of that platform's source tree (for under-development platforms -PDCLib maintainers won't bother with). - -So, to use PDCLib on your given platform, you unpack PDCLib (as you -obviously have done already since you are reading this), and copy -the overlay for your platform over the PDCLib source tree structure. - -Development Status ------------------- - -v0.1 - 2004-12-12 -Freestanding-only C99 implementation without any overlay, and missing -the INTN_C() / UINTN_C() macros. still has the enquire.c -values hardcoded into it; not sure whether to include enquire.c in the -package, to leave to the overlay, or devise some parameterized -macro magic as for / . Not thoroughly tested, but -I had to make the 0.1 release sometime so why not now. - -v0.2 - 2005-01-12 -Adds implementations for (excluding strerror()), INTN_C() / -UINTN_C() macros, and some improvements in the internal headers. -Test drivers still missing, but added warnings about that. - -v0.3 - 2005-11-21 -Adds test drivers, fixes some bugs in . - -v0.4 - 2005-02-06 -Implementations for parts of . Still missing are the floating -point conversions, and the wide-/multibyte-character functions. - -v0.4.1 - 2006-11-16 -With v0.5 () taking longer than expected, v0.4.1 was set up as -a backport of bugfixes in the current development code. -- #1 realloc( NULL, size ) fails (fixed) -- #2 stdlib.h - insufficient documentation (fixed) -- #4 Misspelled name in credits (fixed) -- #5 malloc() splits off too-small nodes (fixed) -- #6 qsort() stack overflow (fixed) -- #7 malloc() bug in list handling (fixed) -- #8 strncmp() does not terminate at '\0' (fixed) -- #9 stdint.h dysfunctional (fixed) -- #10 NULL redefinition warnings (fixed) - -v0.5 - 2010-12-22 -Implementations for , , most parts of , -and strerror() from . -Still no locale / wide-char support. Enabled all GCC compiler warnings I -could find, and fixed everything that threw a warning. (You see this, -maintainers of Open Source software? No warnings whatsoever. Stop telling -me it cannot be done.) Fixed all known bugs in the v0.4 release. - - -A WORD ON THE v0.5 RELEASE -========================== - -The v0.5 release is not well-tested. There are several things in it done -in a way that I would never label "release quality". Some things are not -even in the *structure* I would like them to be. An example for this is -the current handling of errno values: It needlessly introduces dependency -on PDCLib (because I use non-standard values), and the values are placed -in the wrong header (_PDCLIB_int.h instead of _PDCLIB_glue.h where they -would be more appropriate). - -But at some point during the development toward the v0.5 release, I found -that my current PDCLib work schedule simply does not allow me to wait -until every piece of is as I would like it to be. It would -probably take another year or two, and my patience is UP. - -I want this released, and I want to think about something else but - for some time. - -So, expect significant change to how stdio is done in upcoming releases. -Everything *WILL* be stable by the time v1.0 comes around, but until then -you will have to accept that I can only deliver "hobby quality" for now. - +PDCLib - Public Domain C Library +================================ + +License +------- + +Written in 2003-2012 by Martin "Solar" Baute, + 2012- by Owen Shepherd + +To the extent possible under law, the author(s) have dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. This software is distributed without any warranty. + +You should have received a copy of the CC0 Public Domain Dedication along with +this software. If not, see . + +NOTE: Some configuration options may include components under non-public domain + conditions. In particular, selecting ptmalloc3 as the malloc + implementation will cause the incorporation of elements under the BSD + license. + +What is it +---------- + +This is a C Standard Library - what's defined in ISO/IEC 9899 "Information +technology — Programming languages — C" or extensions to the above defined in +ISO/IEC 14882 "Information technology — Programming languages — C++". A few +extensions may optionally be provided. + +Terms for extensions +-------------------- +Extensions are permitted where their inclusion is reasonable, they are widely +used, in keeping with the spirit of the standard, and do not convey +additional requirements upon the target system, and do not needlessly duplicate +functionality already contained within the standard. + +As an example: strdup is in, because (a) it can be implemented entirely in +terms of existing standard C functions and (b) is very widely used. Something +like open, write or close would not be considered, because it implies POSIXy +assumptions. + +Internals +--------- + +As a namespace convention, everything (files, typedefs, functions, +macros) not defined in ISO/IEC 9899 is prefixed with _PDCLIB. +The standard defines any identifiers starting with '_' and a capital +letter as reserved for the implementation, and since the chances of +your compiler using an identifier in the _PDCLIB range are slim, +any strictly conforming application should work with this library. + +PDCLib consists of several parts: + +1) standard headers; +2) implementation files for standard functions; +3) internal header files keeping complex stuff out of the standard + headers; +4) the central, platform-specific file _PDCLIB_config.h; +5) platform-specific implementation files; + +The standard headers (in ./includes/) only contain what they are +defined to contain. Where additional logic or macro magic is +necessary, that is deferred to the internal files. This has been done +so that the headers are actually educational as to what they provide +(as opposed to how the library does it). + +There is a seperate implementation file (in ./function/{header}/) for +every function defined by the standard, named {function}.c. Not only +does this avoid linking in huge amounts of unused code when you use +but a single function, it also allows the optimization overlay to work +(see below). + +(The directory ./functions/_PDCLIB/ contains internal and helper +functions that are not part of the standard.) + +Then there are internal header files (in ./internal/), which contain +all the "black magic" and "code fu" that was kept out of the standard +headers. You should not have to touch them if you want to adapt PDCLib +to a new platform. Note that, if you *do* have to touch them, I would +consider it a serious design flaw, and would be happy to fix it in the +next PDCLib release. Any adaption work should be covered by the steps +detailed below. + +For adapting PDCLib to a new platform (the trinity of CPU, operating +system, and compiler), make a copy of ./platform/example/ named +./platform/{your_platform}/, and modify the files of your copy to suit +the constraints of your platform. When you are done, copy the contents +of your platform directory over the source directory structure +of PDCLib (or link them into the appropriate places). That should be +all that is actually required to make PDCLib work for your platform. + +Future directions +----------------- +Obviously, full C89, C99 and C11 conformance; and full support for the +applicable portions of C++98, C++03 and C++11. + +Support for "optimization overlays." These would allow efficient +implementations of certain functions on individual platforms, for example +memcpy, strcpy and memset. This requires further work to only compile in one +version of a given function. + +Development Status +------------------ + +v0.1 - 2004-12-12 +Freestanding-only C99 implementation without any overlay, and missing +the INTN_C() / UINTN_C() macros. still has the enquire.c +values hardcoded into it; not sure whether to include enquire.c in the +package, to leave to the overlay, or devise some parameterized +macro magic as for / . Not thoroughly tested, but +I had to make the 0.1 release sometime so why not now. + +v0.2 - 2005-01-12 +Adds implementations for (excluding strerror()), INTN_C() / +UINTN_C() macros, and some improvements in the internal headers. +Test drivers still missing, but added warnings about that. + +v0.3 - 2005-11-21 +Adds test drivers, fixes some bugs in . + +v0.4 - 2005-02-06 +Implementations for parts of . Still missing are the floating +point conversions, and the wide-/multibyte-character functions. + +v0.4.1 - 2006-11-16 +With v0.5 () taking longer than expected, v0.4.1 was set up as +a backport of bugfixes in the current development code. +- #1 realloc( NULL, size ) fails (fixed) +- #2 stdlib.h - insufficient documentation (fixed) +- #4 Misspelled name in credits (fixed) +- #5 malloc() splits off too-small nodes (fixed) +- #6 qsort() stack overflow (fixed) +- #7 malloc() bug in list handling (fixed) +- #8 strncmp() does not terminate at '\0' (fixed) +- #9 stdint.h dysfunctional (fixed) +- #10 NULL redefinition warnings (fixed) + +v0.5 - 2010-12-22 +Implementations for , , most parts of , +and strerror() from . +Still no locale / wide-char support. Enabled all GCC compiler warnings I +could find, and fixed everything that threw a warning. (You see this, +maintainers of Open Source software? No warnings whatsoever. Stop telling +me it cannot be done.) Fixed all known bugs in the v0.4 release. + +Near Future +----------- +Current development directions are: + +Implement portions of the C11 standard that have a direct impact on the way +that PDCLib itself is built. For example, in order to support multithreading, +PDCLib needs a threading abstraction; therefore, C11's thread library is being +implemented to provide the backing for this (as there is no purpose in +implementing two abstractions) + +Cleanup portions of , particularly the backend. _PDCLIB_fillbuffer and +_PDCLIB_flushbuffer in particular do not feel 'well' factored and need to know +too much about FILE's internals. + +Modularize the library somewhat. This can already be seen with components under +"opt/". This structure is preliminary; it will likely change as the process +continues. \ No newline at end of file diff --git a/functions/_PDCLIB/assert.c b/functions/_PDCLIB/assert.c index fbee634..8f87912 100644 --- a/functions/_PDCLIB/assert.c +++ b/functions/_PDCLIB/assert.c @@ -12,26 +12,21 @@ #ifndef REGTEST -#ifndef _PDCLIB_AUX_H -#define _PDCLIB_AUX_H _PDCLIB_AUX_H #include <_PDCLIB_aux.h> -#endif -#if _PDCLIB_C_VERSION == 99 -void _PDCLIB_assert( char const * const message1, char const * const function, char const * const message2 ) +void _PDCLIB_assert99( char const * const message1, char const * const function, char const * const message2 ) { fputs( message1, stderr ); fputs( function, stderr ); fputs( message2, stderr ); abort(); } -#else -void _PDCLIB_assert( char const * const message ) + +void _PDCLIB_assert89( char const * const message ) { fputs( message, stderr ); abort(); } -#endif #endif diff --git a/functions/_PDCLIB/atomax.c b/functions/_PDCLIB/atomax.c index 9a70218..45095e7 100644 --- a/functions/_PDCLIB/atomax.c +++ b/functions/_PDCLIB/atomax.c @@ -6,7 +6,6 @@ Permission is granted to use, modify, and / or redistribute at will. */ -#define _PDCLIB_INT_H _PDCLIB_INT_H #include <_PDCLIB_int.h> #include #include diff --git a/functions/_PDCLIB/digits.c b/functions/_PDCLIB/digits.c index 940e962..ad41e5d 100644 --- a/functions/_PDCLIB/digits.c +++ b/functions/_PDCLIB/digits.c @@ -6,10 +6,7 @@ Permission is granted to use, modify, and / or redistribute at will. */ -#ifndef _PDCLIB_INT_H -#define _PDCLIB_INT_H _PDCLIB_INT_H #include <_PDCLIB_int.h> -#endif char _PDCLIB_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; diff --git a/functions/_PDCLIB/errno.c b/functions/_PDCLIB/errno.c index 5ae0ca4..7a69080 100644 --- a/functions/_PDCLIB/errno.c +++ b/functions/_PDCLIB/errno.c @@ -6,7 +6,6 @@ Permission is granted to use, modify, and / or redistribute at will. */ -#define _PDCLIB_INT_H _PDCLIB_INT_H #include <_PDCLIB_int.h> #ifndef REGTEST diff --git a/functions/_PDCLIB/prepread.c b/functions/_PDCLIB/prepread.c index 9111ff4..d2288c7 100644 --- a/functions/_PDCLIB/prepread.c +++ b/functions/_PDCLIB/prepread.c @@ -8,7 +8,6 @@ #include -#define _PDCLIB_GLUE_H _PDCLIB_GLUE_H #include <_PDCLIB_glue.h> int _PDCLIB_prepread( struct _PDCLIB_file_t * stream ) diff --git a/functions/_PDCLIB/stdarg.c b/functions/_PDCLIB/stdarg.c index fb3f4d6..abb1f4c 100644 --- a/functions/_PDCLIB/stdarg.c +++ b/functions/_PDCLIB/stdarg.c @@ -9,6 +9,7 @@ #include #include #include +#ifdef TEST #include <_PDCLIB_test.h> @@ -111,3 +112,4 @@ int main( void ) test( TAG_INTPTR, &x, TAG_LDBLPTR, &d, TAG_FUNCPTR, dummy, TAG_END ); return TEST_RESULTS; } +#endif diff --git a/functions/_PDCLIB/strtox_main.c b/functions/_PDCLIB/strtox_main.c index b19a1e7..1556ec4 100644 --- a/functions/_PDCLIB/strtox_main.c +++ b/functions/_PDCLIB/strtox_main.c @@ -6,7 +6,6 @@ Permission is granted to use, modify, and / or redistribute at will. */ -#define _PDCLIB_INT_H _PDCLIB_INT_H #include <_PDCLIB_int.h> #include #include diff --git a/functions/stdio/fgets.c b/functions/stdio/fgets.c index 7d5801b..44518a3 100644 --- a/functions/stdio/fgets.c +++ b/functions/stdio/fgets.c @@ -10,7 +10,6 @@ #ifndef REGTEST -#define _PDCLIB_GLUE_H _PDCLIB_GLUE_H #include <_PDCLIB_glue.h> char * fgets( char * _PDCLIB_restrict s, int size, struct _PDCLIB_file_t * _PDCLIB_restrict stream ) diff --git a/functions/stdio/fwrite.c b/functions/stdio/fwrite.c index 0ea1b02..89e9c03 100644 --- a/functions/stdio/fwrite.c +++ b/functions/stdio/fwrite.c @@ -15,6 +15,8 @@ #include #include +//TODO OS(2012-08-01): Ascertain purpose of lineend & potentially remove + size_t fwrite( const void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, struct _PDCLIB_file_t * _PDCLIB_restrict stream ) { if ( _PDCLIB_prepwrite( stream ) == EOF ) @@ -22,7 +24,7 @@ size_t fwrite( const void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, str return 0; } _PDCLIB_size_t offset = 0; - bool lineend = false; + //bool lineend = false; size_t nmemb_i; for ( nmemb_i = 0; nmemb_i < nmemb; ++nmemb_i ) { @@ -32,7 +34,7 @@ size_t fwrite( const void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, str { /* Remember last newline, in case we have to do a partial line-buffered flush */ offset = stream->bufidx; - lineend = true; + //lineend = true; } if ( stream->bufidx == stream->bufsize ) { @@ -41,7 +43,7 @@ size_t fwrite( const void * _PDCLIB_restrict ptr, size_t size, size_t nmemb, str /* Returning number of objects completely buffered */ return nmemb_i; } - lineend = false; + //lineend = false; } } } diff --git a/functions/stdio/gets.c b/functions/stdio/gets.c index ac93e97..9bf3a26 100644 --- a/functions/stdio/gets.c +++ b/functions/stdio/gets.c @@ -9,8 +9,6 @@ #include #ifndef REGTEST - -#define _PDCLIB_GLUE_H _PDCLIB_GLUE_H #include <_PDCLIB_glue.h> char * gets( char * s ) diff --git a/functions/string/strdup.c b/functions/string/strdup.c new file mode 100644 index 0000000..ac2200e --- /dev/null +++ b/functions/string/strdup.c @@ -0,0 +1,46 @@ +/* [XSI] char* strdup(const char *) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include +#include + +#ifndef REGTEST + +#pragma weak strdup +char *strdup(const char *s) +{ + char* ns = NULL; + if(s) { + size_t len = strlen(s) + 1; + ns = malloc(len); + if(ns) + strncpy(ns, s, len); + } + return ns; +} + +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> + +int main( void ) +{ + const char *teststr = "Hello, world"; + const char *teststr2 = "An alternative test string with non-7-bit characters \xFE\x8C\n"; + char *testres, *testres2; + + TESTCASE(testres = strdup(teststr)); + TESTCASE(testres2 = strdup(teststr2)); + TESTCASE(strcmp(testres, teststr) == 0); + TESTCASE(strcmp(testres2, teststr2) == 0); + free(testres); + free(testres2); + + return TEST_RESULTS; +} + +#endif diff --git a/includes/assert.h b/includes/assert.h index fb6dbf1..7874167 100644 --- a/includes/assert.h +++ b/includes/assert.h @@ -6,44 +6,40 @@ Permission is granted to use, modify, and / or redistribute at will. */ -#ifndef _PDCLIB_AUX_H -#define _PDCLIB_AUX_H _PDCLIB_AUX_H +#ifndef _PDCLIB_ASSERT_H +#define _PDCLIB_ASSERT_H _PDCLIB_ASSERT_H #include <_PDCLIB_aux.h> -#endif - -#ifndef _PDCLIB_CONFIG_H -#define _PDCLIB_CONFIG_H _PDCLIB_CONFIG_H #include <_PDCLIB_config.h> -#endif +_PDCLIB_BEGIN_EXTERN_C -#ifndef _PDCLIB_ASSERT_H -#define _PDCLIB_ASSERT_H _PDCLIB_ASSERT_H -#if _PDCLIB_C_VERSION == 99 -void _PDCLIB_assert( char const * const, char const * const, char const * const ); -#else -void _PDCLIB_assert( char const * const ); -#endif -#endif +void _PDCLIB_assert99( char const * const, char const * const, char const * const ); +void _PDCLIB_assert89( char const * const ); /* If NDEBUG is set, assert() is a null operation. */ #undef assert #ifdef NDEBUG #define assert( ignore ) ( (void) 0 ) +#elif _PDCLIB_C_VERSION >= 99 +#define assert(expression) \ + do { if(!(expression)) \ + _PDCLIB_assert99("Assertion failed: " #expression \ + ", function ", __func__, \ + ", file " __FILE__ \ + ", line " _PDCLIB_symbol2string( __LINE__ ) \ + "." _PDCLIB_endl ); \ + } while(0) #else -#if _PDCLIB_C_VERSION == 99 -#define assert( expression ) ( ( expression ) ? (void) 0 \ - : _PDCLIB_assert( "Assertion failed: " #expression \ - ", function ", __func__, \ +#define assert(expression) \ + do { \ + if(!(expression)) \ + _PDCLIB_assert89( "Assertion failed: " #expression \ ", file " __FILE__ \ ", line " _PDCLIB_symbol2string( __LINE__ ) \ - "." _PDCLIB_endl ) ) -#else -#define assert( expression ) ( ( expression ) ? (void) 0 \ - : _PDCLIB_assert( "Assertion failed: " #expression \ - ", file " __FILE__ \ - ", line " _PDCLIB_symbol2string( __LINE__ ) \ - "." _PDCLIB_endl ) ) + "." _PDCLIB_endl ); \ + } while(0) #endif + +_PDCLIB_END_EXTERN_C #endif diff --git a/includes/ctype.h b/includes/ctype.h index ae95146..8f979ef 100644 --- a/includes/ctype.h +++ b/includes/ctype.h @@ -8,11 +8,8 @@ #ifndef _PDCLIB_CTYPE_H #define _PDCLIB_CTYPE_H _PDCLIB_CTYPE_H - -#ifndef _PDCLIB_INT_H -#define _PDCLIB_INT_H _PDCLIB_INT_H #include <_PDCLIB_int.h> -#endif +_PDCLIB_BEGIN_EXTERN_C /* Character classification functions */ @@ -95,4 +92,5 @@ int tolower( int c ); */ int toupper( int c ); +_PDCLIB_END_EXTERN_C #endif diff --git a/includes/errno.h b/includes/errno.h index 90c61db..039368c 100644 --- a/includes/errno.h +++ b/includes/errno.h @@ -8,16 +8,14 @@ #ifndef _PDCLIB_ERRNO_H #define _PDCLIB_ERRNO_H _PDCLIB_ERRNO_H - -#ifndef _PDCLIB_INT_H -#define _PDCLIB_INT_H _PDCLIB_INT_H #include <_PDCLIB_int.h> -#endif +_PDCLIB_BEGIN_EXTERN_C #define errno (*_PDCLIB_errno_func()) #define ERANGE _PDCLIB_ERANGE #define EDOM _PDCLIB_EDOM +_PDCLIB_END_EXTERN_C #endif diff --git a/includes/inttypes.h b/includes/inttypes.h index dc9af35..231dfab 100644 --- a/includes/inttypes.h +++ b/includes/inttypes.h @@ -8,8 +8,8 @@ #ifndef _PDCLIB_INTTYPES_H #define _PDCLIB_INTTYPES_H _PDCLIB_INTTYPES_H - #include +_PDCLIB_BEGIN_EXTERN_C typedef struct _PDCLIB_imaxdiv_t imaxdiv_t; @@ -248,5 +248,6 @@ uintmax_t strtoumax( const char * _PDCLIB_restrict nptr, char * * _PDCLIB_restri /* TODO: wcstoimax(), wcstoumax() */ +_PDCLIB_END_EXTERN_C #endif diff --git a/includes/iso646.h b/includes/iso646.h index a97817e..80159fc 100644 --- a/includes/iso646.h +++ b/includes/iso646.h @@ -9,6 +9,7 @@ #ifndef _PDCLIB_ISO646_H #define _PDCLIB_ISO646_H _PDCLIB_ISO646_H +#ifndef __cplusplus #define and && #define and_eq &= #define bitand & @@ -20,6 +21,7 @@ #define or_eq |= #define xor ^ #define xor_eq ^= +#endif #endif diff --git a/includes/limits.h b/includes/limits.h index 5eeaf10..998aa39 100644 --- a/includes/limits.h +++ b/includes/limits.h @@ -8,11 +8,7 @@ #ifndef _PDCLIB_LIMITS_H #define _PDCLIB_LIMITS_H _PDCLIB_LIMITS_H - -#ifndef _PDCLIB_INT_H -#define _PDCLIB_INT_H _PDCLIB_INT_H #include <_PDCLIB_int.h> -#endif /* TODO: Defined to 1 as multibyte characters are not supported yet. */ #define MB_LEN_MAX 1 diff --git a/includes/locale.h b/includes/locale.h index 82fc21b..6d9d482 100644 --- a/includes/locale.h +++ b/includes/locale.h @@ -8,11 +8,8 @@ #ifndef _PDCLIB_LOCALE_H #define _PDCLIB_LOCALE_H _PDCLIB_LOCALE_H - -#ifndef _PDCLIB_INT_H -#define _PDCLIB_INT_H _PDCLIB_INT_H #include <_PDCLIB_int.h> -#endif +_PDCLIB_BEGIN_EXTERN_C #ifndef _PDCLIB_NULL_DEFINED #define _PDCLIB_NULL_DEFINED _PDCLIB_NULL_DEFINED @@ -100,5 +97,6 @@ char * setlocale( int category, const char * locale ); */ struct lconv * localeconv( void ); +_PDCLIB_END_EXTERN_C #endif diff --git a/includes/stdarg.h b/includes/stdarg.h index e75cd55..202d372 100644 --- a/includes/stdarg.h +++ b/includes/stdarg.h @@ -8,11 +8,9 @@ #ifndef _PDCLIB_STDARG_H #define _PDCLIB_STDARG_H _PDCLIB_STDARG_H - -#ifndef _PDCLIB_CONFIG_H -#define _PDCLIB_CONFIG_H _PDCLIB_CONFIG_H +#include <_PDCLIB_aux.h> #include <_PDCLIB_config.h> -#endif +_PDCLIB_BEGIN_EXTERN_C typedef _PDCLIB_va_list va_list; @@ -21,5 +19,6 @@ typedef _PDCLIB_va_list va_list; #define va_end( ap ) _PDCLIB_va_end( ap ) #define va_start( ap, parmN ) _PDCLIB_va_start( ap, parmN ) +_PDCLIB_END_EXTERN_C #endif diff --git a/includes/stdbool.h b/includes/stdbool.h index 66166e1..a01cc2f 100644 --- a/includes/stdbool.h +++ b/includes/stdbool.h @@ -9,9 +9,12 @@ #ifndef _PDCLIB_STDBOOL_H #define _PDCLIB_STDBOOL_H _PDCLIB_STDBOOL_H +#ifndef __cplusplus #define bool _Bool #define true 1 #define false 0 +#endif + #define __bool_true_false_are_defined 1 #endif diff --git a/includes/stddef.h b/includes/stddef.h index 8968577..6d8c03a 100644 --- a/includes/stddef.h +++ b/includes/stddef.h @@ -8,16 +8,9 @@ #ifndef _PDCLIB_STDDEF_H #define _PDCLIB_STDDEF_H _PDCLIB_STDDEF_H - -#ifndef _PDCLIB_CONFIG_H -#define _PDCLIB_CONFIG_H _PDCLIB_CONFIG_H #include <_PDCLIB_config.h> -#endif - -#ifndef _PDCLIB_INT_H -#define _PDCLIB_INT_H _PDCLIB_INT_H #include <_PDCLIB_int.h> -#endif +_PDCLIB_BEGIN_EXTERN_C typedef _PDCLIB_ptrdiff_t ptrdiff_t; @@ -26,7 +19,9 @@ typedef _PDCLIB_ptrdiff_t ptrdiff_t; typedef _PDCLIB_size_t size_t; #endif +#ifndef __cplusplus typedef _PDCLIB_wchar_t wchar_t; +#endif #ifndef _PDCLIB_NULL_DEFINED #define _PDCLIB_NULL_DEFINED _PDCLIB_NULL_DEFINED @@ -35,5 +30,6 @@ typedef _PDCLIB_wchar_t wchar_t; #define offsetof( type, member ) _PDCLIB_offsetof( type, member ) +_PDCLIB_END_EXTERN_C #endif diff --git a/includes/stdint.h b/includes/stdint.h index a5dfc5c..2a76836 100644 --- a/includes/stdint.h +++ b/includes/stdint.h @@ -8,11 +8,7 @@ #ifndef _PDCLIB_STDINT_H #define _PDCLIB_STDINT_H _PDCLIB_STDINT_H - -#ifndef _PDCLIB_INT_H -#define _PDCLIB_INT_H _PDCLIB_INT_H #include <_PDCLIB_int.h> -#endif /* 7.18.1.1 Exact-width integer types. */ diff --git a/includes/stdio.h b/includes/stdio.h index a2428a5..1d7c0bf 100644 --- a/includes/stdio.h +++ b/includes/stdio.h @@ -8,11 +8,8 @@ #ifndef _PDCLIB_STDIO_H #define _PDCLIB_STDIO_H _PDCLIB_STDIO_H - -#ifndef _PDCLIB_INT_H -#define _PDCLIB_INT_H _PDCLIB_INT_H #include <_PDCLIB_int.h> -#endif +_PDCLIB_BEGIN_EXTERN_C #ifndef _PDCLIB_SIZE_T_DEFINED #define _PDCLIB_SIZE_T_DEFINED _PDCLIB_SIZE_T_DEFINED @@ -65,7 +62,7 @@ int remove( const char * filename ); If there already is a file with the new filename, behaviour is defined by the glue code (see functions/_PDCLIB/rename.c). */ -int rename( const char * old, const char * new ); +int rename( const char * old, const char * newn ); /* Open a temporary file with mode "wb+", i.e. binary-update. Remove the file automatically if it is closed or the program exits normally (by returning @@ -796,4 +793,5 @@ int ferror( FILE * stream ); */ void perror( const char * s ); +_PDCLIB_END_EXTERN_C #endif diff --git a/includes/stdlib.h b/includes/stdlib.h index b035c9c..15f07b0 100644 --- a/includes/stdlib.h +++ b/includes/stdlib.h @@ -8,11 +8,8 @@ #ifndef _PDCLIB_STDLIB_H #define _PDCLIB_STDLIB_H _PDCLIB_STDLIB_H - -#ifndef _PDCLIB_INT_H -#define _PDCLIB_INT_H _PDCLIB_INT_H #include <_PDCLIB_int.h> -#endif +_PDCLIB_BEGIN_EXTERN_C #ifndef _PDCLIB_SIZE_T_DEFINED #define _PDCLIB_SIZE_T_DEFINED _PDCLIB_SIZE_T_DEFINED @@ -141,7 +138,7 @@ void * realloc( void * ptr, size_t size ); temporary files before exiting with EXIT_FAILURE. abort() does not return. */ -void abort( void ); +_PDCLIB_noreturn void abort( void ); /* Register a function that will be called on exit(), or when main() returns. At least 32 functions can be registered this way, and will be called in @@ -156,7 +153,7 @@ int atexit( void (*func)( void ) ); and EXIT_FAILURE above.) exit() does not return. */ -void exit( int status ); +_PDCLIB_noreturn void exit( int status ); /* Normal process termination. Functions registered by atexit() (see above) are NOT CALLED. This implementation DOES flush streams, close files and removes @@ -164,7 +161,7 @@ void exit( int status ); comment for EXIT_SUCCESS and EXIT_FAILURE above.) _Exit() does not return. */ -void _Exit( int status ); +_PDCLIB_noreturn void _Exit( int status ); /* Search an environment-provided key-value map for the given key name, and return a pointer to the associated value string (or NULL if key name cannot @@ -244,4 +241,5 @@ size_t mbstowcs( wchar_t * _PDCLIB_restrict pwcs, const char * _PDCLIB_restrict size_t wcstombs( char * _PDCLIB_restrict s, const wchar_t * _PDCLIB_restrict pwcs, size_t n ); */ +_PDCLIB_END_EXTERN_C #endif diff --git a/includes/stdnoreturn.h b/includes/stdnoreturn.h new file mode 100644 index 0000000..5997ff6 --- /dev/null +++ b/includes/stdnoreturn.h @@ -0,0 +1,16 @@ +#ifndef _PDCLIB_STDNORETURN_H +#define _PDCLIB_STDNORETURN_H +#include <_PDCLIB_aux.h> + +#ifndef __cplusplus +/* This is problematic - if we don't define it, then C code can't be compiled + * on a C++ compiler. If we do define it, then we break all instances of C++ + * [[noreturn]] + * + * This does not appear well thought out... + */ +#define noreturn _PDCLIB_noreturn +#endif + + +#endif diff --git a/includes/string.h b/includes/string.h index c5f74b5..d2b22e1 100644 --- a/includes/string.h +++ b/includes/string.h @@ -8,11 +8,8 @@ #ifndef _PDCLIB_STRING_H #define _PDCLIB_STRING_H _PDCLIB_STRING_H - -#ifndef _PDCLIB_INT_H -#define _PDCLIB_INT_H _PDCLIB_INT_H #include <_PDCLIB_int.h> -#endif +_PDCLIB_BEGIN_EXTERN_C #ifndef _PDCLIB_SIZE_T_DEFINED #define _PDCLIB_SIZE_T_DEFINED _PDCLIB_SIZE_T_DEFINED @@ -187,4 +184,9 @@ char * strerror( int errnum ); */ size_t strlen( const char * s ); +#ifdef _PDCLIB_POSIX_EX +char * strdup( const char* src ); +#endif + +_PDCLIB_END_EXTERN_C #endif diff --git a/includes/threads.h b/includes/threads.h new file mode 100644 index 0000000..5de3d38 --- /dev/null +++ b/includes/threads.h @@ -0,0 +1,98 @@ +#ifndef _PDCLIB_THREADS_H +#define _PDCLIB_THREADS_H +#include <_PDCLIB_threadconfig.h> +#include +_PDCLIB_BEGIN_EXTERN_C + +#define thread_local _Thread_local + +typedef _PDCLIB_once_flag once_flag; + +enum { + mtx_plain = 0, + mtx_recursive = (1 << 0), + mtx_timed = (1 << 1), + + _PDCLIB_mtx_valid_mask = mtx_recursive | mtx_timed +}; + +enum { + thrd_success = 0, + thrd_timeout = 1, + thrd_busy = 2, + thrd_error = 3, + thrd_nomem = 4, +}; + +#define ONCE_FLAG_INIT _PDCLIB_ONCE_FLAG_INIT +#if defined(_PDCLIB_ONCE_FLAG_DONE) +static inline void call_once(once_flag *flag, void (*func)(void)) +{ + if(*flag != _PDCLIB_ONCE_FLAG_DONE) { + _PDCLIB_call_once(flag, func); + } +} +#else +void call_once(once_flag *flag, void (*func)(void)) +#endif + +#if defined(_PDCLIB_MTX_T) +typedef _PDCLIB_MTX_T mtx_t; +void mtx_destroy(mtx_t *mtx); +int mtx_init(mtx_t *mtx, int type); +int mtx_lock(mtx_t *mtx); +int mtx_timedlock(mtx_t *_PDCLIB_restrict mtx, const struct timespec *_PDCLIB_restrict ts); +int mtx_trylock(mtx_t *mtx); +int mtx_unlock(mtx_t *mtx); +#endif + +#if defined(_PDCLIB_CND_T) +typedef _PDCLIB_CND_T cnd_t; +int cnd_broadcast(cnd_t *cond); +void cnd_destroy(cnd_t *cond); +int cnd_init(cnd_t *cond); +int cnd_signal(cnd_t *cond); +int cnd_timedwait(cnd_t *_PDCLIB_restrict cond, + mtx_t *_PDCLIB_restrict mtx, + const struct timespec *_PDCLIB_restrict ts); +int cnd_wait(cnd_t *cond, mtx_t *mtx); +#endif + +#if defined(_PDCLIB_THRD_T) +#define _PDCLIB_THRD_HAVE_MISC +typedef _PDCLIB_THRD_T thrd_t; +typedef int (*)(void*) thrd_start_t; + +int thrd_create(thrd_t *thr, thrd_start_t func, void *arg); +thrd_t thrd_current(void); +int thrd_detach(thrd_t thr); +int thrd_equal(thrd_t thr0, thrd_t thr1); +_PDCLIB_noreturn void thrd_exit(int res); +int thrd_join(thrd_t thr, int *res); +#endif + +#if defined(_PDCLIB_THRD_HAVE_MISC) +int thrd_sleep(const struct timespec *duration, struct timespec *remaining); +void thrd_yield(void); +#endif + +/* The behaviour of tss_t is woefully underspecified in the C11 standard. In + * particular, it never specifies where/when/if destructors are called. + * + * In lieu of any clarification, we assume the behaviour of POSIX pthread_key_t + */ + +#if defined(_PDCLIB_TSS_T) +#define TSS_DTOR_ITERATIONS _PDCLIB_TSS_DTOR_ITERATIONS + +typedef _PDCLIB_TSS_T tss_t; +typedef void (*tss_dtor_t)(void*); + +int tss_create(tss_t *key, tss_dtor_t dtor); +void tss_delete(tss_t key); +void *tss_get(tss_t key); +int tss_set(tss_t key, void *val); +#endif + +_PDCLIB_END_EXTERN_C +#endif diff --git a/includes/time.h b/includes/time.h new file mode 100644 index 0000000..3fc090e --- /dev/null +++ b/includes/time.h @@ -0,0 +1,31 @@ +#ifndef _PDCLIB_TIME_H +#define _PDCLIB_TIME_H +#include <_PDCLIB_aux.h> +#include <_PDCLIB_int.h> + +_PDCLIB_BEGIN_EXTERN_C +#ifndef _PDCLIB_SIZE_T_DEFINED +#define _PDCLIB_SIZE_T_DEFINED _PDCLIB_SIZE_T_DEFINED +typedef _PDCLIB_size_t size_t; +#endif + +#ifndef _PDCLIB_NULL_DEFINED +#define _PDCLIB_NULL_DEFINED _PDCLIB_NULL_DEFINED +#define NULL _PDCLIB_NULL +#endif + +typedef _PDCLIB_time_t time_t; +typedef _PDCLIB_clock_t clock_t; + +#ifndef _PDCLIB_STRUCT_TIMESPEC_DEFINED +#define _PDCLIB_STRUCT_TIMESPEC_DEFINED +_PDCLIB_DEFINE_STRUCT_TIMESPEC() +#endif + +#ifndef _PDCLIB_STRUCT_TM_DEFINED +#define _PDCLIB_STRUCT_TM_DEFINED +_PDCLIB_DEFINE_STRUCT_TM() +#endif + +_PDCLIB_END_EXTERN_C +#endif diff --git a/internals/_PDCLIB_aux.h b/internals/_PDCLIB_aux.h index 15c5db6..d34dfb5 100644 --- a/internals/_PDCLIB_aux.h +++ b/internals/_PDCLIB_aux.h @@ -1,4 +1,5 @@ -/* $Id$ */ +#ifndef _PDCLIB_AUX_H +#define _PDCLIB_AUX_H /* Auxiliary PDCLib code <_PDCLIB_aux.h> @@ -21,20 +22,71 @@ #error Compiler does not define _ _STDC_ _ to 1 (not standard-compliant)! #endif -#ifndef __STDC_VERSION__ -#define _PDCLIB_C_VERSION 90 -#define _PDCLIB_restrict -#define _PDCLIB_inline +#if defined(_PDCLIB_C_VERSION) + /* Pass - conditional simplification case */ +#elif !defined(__STDC_VERSION__) + #define _PDCLIB_C_VERSION 1990 #elif __STDC_VERSION__ == 199409L -#define _PDCLIB_C_VERSION 95 -#define _PDCLIB_restrict -#define _PDCLIB_inline + #define _PDCLIB_C_VERSION 1995 #elif __STDC_VERSION__ == 199901L -#define _PDCLIB_C_VERSION 99 -#define _PDCLIB_restrict restrict -#define _PDCLIB_inline inline + #define _PDCLIB_C_VERSION 1999 +#elif __STDC_VERSION__ == 201112L + #define _PDCLIB_C_VERSION 2011 #else -#error Unsupported _ _STDC_VERSION_ _ (__STDC_VERSION__) (supported: ISO/IEC 9899:1990, 9899/AMD1:1995, and 9899:1999). + #error Unsupported _ _STDC_VERSION_ _ (__STDC_VERSION__) (supported: ISO/IEC 9899:1990, 9899/AMD1:1995, 9899:1999, 9899:2011). +#endif + +#if !defined(__cplusplus) || defined(_PDCLIB_CXX_VERSION) + /* Pass - conditional simplification case */ +#elif __cplusplus == 201103L + #define _PDCLIB_CXX_VERSION 2011 + #if _PDCLIB_C_VERSION < 2011 + #undef _PDCLIB_C_VERSION + #define _PDCLIB_C_VERSION 2011 + #endif +#elif __cplusplus == 199711L + #define _PDCLIB_CXX_VERSION 1997 +#else + #error Unsupported _ _cplusplus (__cplusplus) (supported: ISO/IEC 14882:1997, ISO/IEC 14882:2011). +#endif + +#if _PDCLIB_C_VERSION >= 1999 || defined(__cplusplus) + #ifndef __cplusplus + #define _PDCLIB_restrict restrict + #endif + #define _PDCLIB_inline inline +#endif + +#if _PDCLIB_CXX_VERSION >= 2011 + #define _PDCLIB_noreturn [[noreturn]] +#elif _PDCLIB_C_VERSION >= 2011 + #define _PDCLIB_noreturn _Noreturn +#endif + +#ifdef __GNUC__ + #ifndef _PDCLIB_restrict + #define _PDCLIB_restrict __restrict + #endif + + #ifndef _PDCLIB_inline + #define _PDCLIB_inline __inline + #endif + + #ifndef _PDCLIB_noreturn + #define _PDCLIB_noreturn __attribute__((noreturn)) + #endif +#endif + +#ifndef _PDCLIB_restrict + #define _PDCLIB_restrict +#endif + +#ifndef _PDCLIB_inline + #define _PDCLIB_inline +#endif + +#ifndef _PDCLIB_noreturn + #define _PDCLIB_noreturn #endif #ifndef __STDC_HOSTED__ @@ -47,10 +99,18 @@ #error Compiler does not define _ _STDC_HOSTED_ _ to 0 or 1 (not standard-compliant)! #endif -#if _PDCLIB_C_VERSION != 99 -#error PDCLib might not be fully conforming to either C89 or C95 prior to v2.x. +#ifdef __cplusplus + #define _PDCLIB_BEGIN_EXTERN_C extern "C" { + #define _PDCLIB_END_EXTERN_C } +#else + #define _PDCLIB_BEGIN_EXTERN_C + #define _PDCLIB_END_EXTERN_C #endif +/*#if _PDCLIB_C_VERSION != 1999 +#error PDCLib might not be fully conforming to either C89 or C95 prior to v2.x. +#endif*/ + /* -------------------------------------------------------------------------- */ /* Helper macros: */ /* _PDCLIB_cc( x, y ) concatenates two preprocessor tokens without extending */ @@ -63,3 +123,11 @@ #define _PDCLIB_symbol2value( x ) #x #define _PDCLIB_symbol2string( x ) _PDCLIB_symbol2value( x ) +#ifndef __PDCLIB_PURE + #define __PDCLIB_PURE 0 +#endif + +#ifndef _PDCLIB_POSIX_EX + #define _PDCLIB_POSIX_EX (!__PDCLIB_PURE) +#endif +#endif \ No newline at end of file diff --git a/internals/_PDCLIB_glue.h b/internals/_PDCLIB_glue.h index 3c5872b..f946cf5 100644 --- a/internals/_PDCLIB_glue.h +++ b/internals/_PDCLIB_glue.h @@ -1,3 +1,5 @@ +#ifndef _PDCLIB_GLUE_H +#define _PDCLIB_GLUE_H /* $Id$ */ /* OS glue functions declaration <_PDCLIB_glue.h> @@ -6,10 +8,8 @@ Permission is granted to use, modify, and / or redistribute at will. */ -#ifndef _PDCLIB_INT_H -#define _PDCLIB_INT_H _PDCLIB_INT_H #include <_PDCLIB_int.h> -#endif +_PDCLIB_BEGIN_EXTERN_C /* -------------------------------------------------------------------------- */ /* OS "glue", part 2 */ @@ -73,5 +73,7 @@ int _PDCLIB_remove( const char * filename ); must still be accessible by old name. Any handling of open files etc. is done by standard rename() already. */ -int _PDCLIB_rename( const char * old, const char * new ); +int _PDCLIB_rename( const char * old, const char * newn); +_PDCLIB_END_EXTERN_C +#endif diff --git a/internals/_PDCLIB_int.h b/internals/_PDCLIB_int.h index a46c2dc..4477fc1 100644 --- a/internals/_PDCLIB_int.h +++ b/internals/_PDCLIB_int.h @@ -1,4 +1,5 @@ -/* $Id$ */ +#ifndef _PDCLIB_INT_H +#define _PDCLIB_INT_H /* PDCLib internal integer logic <_PDCLIB_int.h> @@ -11,15 +12,8 @@ /* would be considered a bug / missing feature: notify the author(s). */ /* -------------------------------------------------------------------------- */ -#ifndef _PDCLIB_CONFIG_H -#define _PDCLIB_CONFIG_H _PDCLIB_CONFIG_H #include <_PDCLIB_config.h> -#endif - -#ifndef _PDCLIB_AUX_H -#define _PDCLIB_AUX_H _PDCLIB_AUX_H #include <_PDCLIB_aux.h> -#endif /* null pointer constant */ #define _PDCLIB_NULL 0 @@ -254,6 +248,36 @@ typedef unsigned _PDCLIB_intmax _PDCLIB_uintmax_t; #define _PDCLIB_INTMAX_C( value ) _PDCLIB_concat( value, _PDCLIB_INTMAX_LITERAL ) #define _PDCLIB_UINTMAX_C( value ) _PDCLIB_concat( value, _PDCLIB_concat( u, _PDCLIB_INTMAX_LITERAL ) ) +/* -------------------------------------------------------------------------- */ +/* Various internals */ +/* -------------------------------------------------------------------------- */ + +typedef _PDCLIB_time _PDCLIB_time_t; +typedef _PDCLIB_clock _PDCLIB_clock_t; + +#if !defined(_PDCLIB_DEFINE_STRUCT_TIMESPEC) +#define _PDCLIB_DEFINE_STRUCT_TIMESPEC() \ + struct timespec { \ + time_t tv_sec; \ + long tv_nsec; \ + }; +#endif + +#if !defined(_PDCLIB_DEFINE_STRUCT_TM) +#define _PDCLIB_DEFINE_STRUCT_TM() \ + struct tm { \ + int tm_sec; \ + int tm_min; \ + int tm_hour; \ + int tm_mday; \ + int tm_mon; \ + int tm_year; \ + int tm_wday; \ + int tm_yday; \ + int tm_isdst; \ + }; +#endif + /* -------------------------------------------------------------------------- */ /* Various internals */ /* -------------------------------------------------------------------------- */ @@ -442,3 +466,4 @@ struct _PDCLIB_ctype_t unsigned char collation; }; +#endif diff --git a/opt/malloc-solar/calloc.c b/opt/malloc-solar/calloc.c new file mode 100644 index 0000000..a2dc21f --- /dev/null +++ b/opt/malloc-solar/calloc.c @@ -0,0 +1,49 @@ +/* $Id$ */ + +/* void * calloc( size_t, size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include +#include + +#ifndef REGTEST + +void * calloc( size_t nmemb, size_t size ) +{ + /* assign memory for nmemb elements of given size */ + void * rc = malloc( nmemb * size ); + if ( rc != NULL ) + { + /* zero-initialize the memory */ + memset( rc, 0, nmemb * size ); + } + return rc; +} + +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> + +int main( void ) +{ + char * s; + TESTCASE( ( s = calloc( 3, 2 ) ) != NULL ); + TESTCASE( s[0] == '\0' ); + TESTCASE( s[5] == '\0' ); + free( s ); + TESTCASE( ( s = calloc( 6, 1 ) ) != NULL ); + TESTCASE( s[0] == '\0' ); + TESTCASE( s[5] == '\0' ); + free( s ); + TESTCASE( ( s = calloc( 1, 6 ) ) != NULL ); + TESTCASE( s[0] == '\0' ); + TESTCASE( s[5] == '\0' ); + free( s ); + return TEST_RESULTS; +} + +#endif diff --git a/opt/malloc-solar/free.c b/opt/malloc-solar/free.c new file mode 100644 index 0000000..4370487 --- /dev/null +++ b/opt/malloc-solar/free.c @@ -0,0 +1,55 @@ +/* $Id$ */ + +/* void free( void * ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include + +#ifndef REGTEST + +#ifndef _PDCLIB_INT_H +#define _PDCLIB_INT_H _PDCLIB_INT_H +#include <_PDCLIB_int.h> +#endif + +/* TODO: Primitive placeholder. Much room for improvement. */ + +/* structure holding first and last element of free node list */ +extern struct _PDCLIB_headnode_t _PDCLIB_memlist; + +void free( void * ptr ) +{ + if ( ptr == NULL ) + { + return; + } + ptr = (void *)( (char *)ptr - sizeof( struct _PDCLIB_memnode_t ) ); + ( (struct _PDCLIB_memnode_t *)ptr )->next = NULL; + if ( _PDCLIB_memlist.last != NULL ) + { + _PDCLIB_memlist.last->next = ptr; + } + else + { + _PDCLIB_memlist.first = ptr; + } + _PDCLIB_memlist.last = ptr; +} + +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> +#include + +int main( void ) +{ + free( NULL ); + TESTCASE( true ); + return TEST_RESULTS; +} + +#endif diff --git a/opt/malloc-solar/malloc.c b/opt/malloc-solar/malloc.c new file mode 100644 index 0000000..991bdd5 --- /dev/null +++ b/opt/malloc-solar/malloc.c @@ -0,0 +1,425 @@ +/* $Id$ */ + +/* void * malloc( size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include +#include +#include + +#ifndef REGTEST +#include <_PDCLIB_glue.h> + +/* TODO: Primitive placeholder. Much room for improvement. */ + +/* Keeping pointers to the first and the last element of the free list. */ +struct _PDCLIB_headnode_t _PDCLIB_memlist = { NULL, NULL }; + +void * malloc( size_t size ) +{ + if ( size == 0 ) + { + return NULL; + } + if ( size < _PDCLIB_MINALLOC ) + { + size = _PDCLIB_MINALLOC; + } + { + struct _PDCLIB_memnode_t * current = _PDCLIB_memlist.first; + struct _PDCLIB_memnode_t * previous = NULL; + struct _PDCLIB_memnode_t * firstfit = NULL; + struct _PDCLIB_memnode_t * firstfit_previous = NULL; + /* Trying exact fit */ + while ( current != NULL ) + { + if ( current->size == size ) + { + /* Found exact fit, allocate node */ + if ( previous != NULL ) + { + /* Node in the middle of the list */ + previous->next = current->next; + } + else + { + /* Node is first in list */ + _PDCLIB_memlist.first = current->next; + } + if ( _PDCLIB_memlist.last == current ) + { + /* Node is last in list */ + _PDCLIB_memlist.last = previous; + } + return (char *)current + sizeof( struct _PDCLIB_memnode_t ); + } + else if ( current->size > size && ( firstfit == NULL || current->size < firstfit->size ) ) + { + /* Remember previous node in case we do not get an exact fit. + Note that this is the node *pointing to* the first fit, + as we need that for allocating (i.e., changing next pointer). + */ + firstfit_previous = previous; + firstfit = current; + } + /* Skip to next node */ + previous = current; + current = current->next; + } + /* No exact fit; go for first fit */ + if ( firstfit != NULL ) + { + bool node_split = false; + if ( ( firstfit->size - size ) > ( _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ) ) ) + { + /* Oversized - split into two nodes */ + struct _PDCLIB_memnode_t * newnode = (struct _PDCLIB_memnode_t *)( (char *)firstfit + sizeof( struct _PDCLIB_memnode_t ) + size ); + newnode->size = firstfit->size - size - sizeof( struct _PDCLIB_memnode_t ); + newnode->next = firstfit->next; + firstfit->next = newnode; + firstfit->size = firstfit->size - newnode->size - sizeof( struct _PDCLIB_memnode_t ); + node_split = true; + } + if ( firstfit_previous != NULL ) + { + /* Node in the middle of the list */ + firstfit_previous->next = firstfit->next; + } + else + { + /* Node is first in list */ + _PDCLIB_memlist.first = firstfit->next; + } + if ( _PDCLIB_memlist.last == firstfit ) + { + /* Node is last in list */ + if ( node_split ) + { + _PDCLIB_memlist.last = firstfit->next; + } + else + { + _PDCLIB_memlist.last = firstfit_previous; + } + } + return (char *)firstfit + sizeof( struct _PDCLIB_memnode_t ); + } + } + { + /* No fit possible; how many additional pages do we need? */ + size_t pages = ( ( size + sizeof( struct _PDCLIB_memnode_t ) - 1 ) / _PDCLIB_PAGESIZE ) + 1; + /* Allocate more pages */ + struct _PDCLIB_memnode_t * newnode = (struct _PDCLIB_memnode_t *)_PDCLIB_allocpages( (int)pages ); + if ( newnode != NULL ) + { + newnode->next = NULL; + newnode->size = pages * _PDCLIB_PAGESIZE - sizeof( struct _PDCLIB_memnode_t ); + if ( ( newnode->size - size ) > ( _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ) ) ) + { + /* Oversized - split into two nodes */ + struct _PDCLIB_memnode_t * splitnode = (struct _PDCLIB_memnode_t *)( (char *)newnode + sizeof( struct _PDCLIB_memnode_t ) + size ); + splitnode->size = newnode->size - size - sizeof( struct _PDCLIB_memnode_t ); + newnode->size = size; + /* Add splitted node as last element to free node list */ + if ( _PDCLIB_memlist.last == NULL ) + { + _PDCLIB_memlist.first = splitnode; + } + else + { + _PDCLIB_memlist.last->next = splitnode; + } + splitnode->next = NULL; /* TODO: This is bug #7, uncovered by testdriver yet. */ + _PDCLIB_memlist.last = splitnode; + } + return (char *)newnode + sizeof( struct _PDCLIB_memnode_t ); + } + } + /* No fit, heap extension not possible - out of memory */ + return NULL; +} + +#endif + + +#ifdef TEST +#include <_PDCLIB_test.h> +#include +#include +#include + + +#ifndef REGTEST + +/* Effective page size, i.e. how many bytes can be allocated and still be on + one page of memory. +*/ +#define EFFECTIVE _PDCLIB_PAGESIZE - sizeof( struct _PDCLIB_memnode_t ) +#define MEMTEST( ptr, size ) ( ( ptr = malloc( size ) ) != NULL ) && ( memset( ptr, 0, size ) == ptr ) + +char * pages_start = 0; +int test_nodes( char const * const, int, ... ); +void PRINT( char const * const, ... ); + +/* This can be enabled to give a dump of node information */ +#if 0 +void PRINT( char const * const format, ... ) +{ + va_list( ap ); + va_start( ap, format ); + vprintf( format, ap ); +} +#else +void PRINT( char const * const format, ... ) +{ + /* EMPTY */ +} +#endif + +/* Helper function checking number of allocated memory pages and the nodes + in the free memory list against expectations. +*/ +int test_nodes( char const * const action, int expected_pages, ... ) +{ + static int count = 1; + int result = 1; + PRINT( action ); + /* Determining the amount of allocated pages */ + int allocated_pages = ( (intptr_t)_PDCLIB_allocpages( 0 ) - (intptr_t)pages_start ) / _PDCLIB_PAGESIZE; + PRINT( "Test #%2d, %d allocated pages", count++, allocated_pages ); + if ( allocated_pages != expected_pages ) + { + PRINT( " - MISMATCH, expected\n %d pages\n", expected_pages ); + result = 0; + } + else + { + PRINT( "\n" ); + } + /* Now moving through the free nodes list */ + va_list( ap ); + va_start( ap, expected_pages ); + struct _PDCLIB_memnode_t * tracer = _PDCLIB_memlist.first; + int firstnode = 0; + int lastnode = 0; + while ( tracer != NULL ) + { + /* Data from node */ + size_t node_location = (char *)tracer - (char *)pages_start; + PRINT( " - node %.4p, size %#.4x", node_location, tracer->size ); + /* Expected data */ + size_t expected_location = va_arg( ap, size_t ); + if ( expected_location == 0 ) + { + PRINT( " - UNEXPECTED NODE\n" ); + result = 0; + continue; + } + /* Memorizing first and last expected node for later comparison. */ + if ( firstnode == 0 ) + { + firstnode = expected_location; + } + lastnode = expected_location; + /* Comparing expected node against current node */ + size_t expected_size = va_arg( ap, size_t ); + if ( ( node_location != expected_location ) || ( tracer->size != expected_size ) ) + { + PRINT( " - MISMATCH, expected values\n %.4p %#.4p\n", expected_location, expected_size ); + result = 0; + } + else + { + PRINT( "\n" ); + } + tracer = tracer->next; + } + /* Comparing first and last node in memlist against expectations. */ + PRINT( " - memlist first: %#.4x - last: %#.4x", + ( _PDCLIB_memlist.first == NULL ) ? NULL : (char *)_PDCLIB_memlist.first - (char *)pages_start, + ( _PDCLIB_memlist.last == NULL ) ? NULL : (char *)_PDCLIB_memlist.last - (char *)pages_start ); + if ( ( firstnode != 0 ) && + ( ( ( (char *)_PDCLIB_memlist.first - (char *)pages_start ) != firstnode ) + || ( ( (char *)_PDCLIB_memlist.last - (char *)pages_start ) != lastnode ) ) ) + { + PRINT( " - MISMATCH, expected values\n %#.4x - last: %#.4x\n", firstnode, lastnode ); + result = 0; + } + else + { + PRINT( "\n" ); + } + PRINT( "\n" ); + return result; +} + +#endif + +/* Note that this test driver heavily tests *internals* of the implementation + above (and of free() and realloc(), too). That means that changes in the + implementation must be accompanied with appropriate changes of the test + driver. It does *not* make a good regression tester for the implementation, + I am afraid, and thus there is no REGTEST equivalent. +*/ + +int main( void ) +{ +#ifndef REGTEST + void * ptr1, * ptr2, * ptr3, * ptr4, * ptr5, * ptr6, * ptr7, * ptr8, * ptr9, * ptrA, * ptrB, * ptrC; + + pages_start = _PDCLIB_allocpages( 0 ); + PRINT( "\nEffective is: %#.4x\nsizeof( memnode ) is: %#.2x\n\n", EFFECTIVE, sizeof( struct _PDCLIB_memnode_t ) ); + + /* Allocating 10 bytes; expecting one page allocation and a node split */ + TESTCASE( MEMTEST( ptr1, 10 ) ); + TESTCASE( test_nodes( "Allocating 10 bytes.", 1, + sizeof( struct _PDCLIB_memnode_t ) + 10, EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - 10, + 0 ) ); + + /* Allocating the rest of the page; expecting no page allocation and assignment of the remaining node */ + TESTCASE( MEMTEST( ptr2, EFFECTIVE - 10 - sizeof( struct _PDCLIB_memnode_t ) ) ); + TESTCASE( test_nodes( "Allocating the rest of the page.", 1, + 0 ) ); + + /* Allocating a full page; expecting one page allocation, no node split */ + TESTCASE( MEMTEST( ptr3, EFFECTIVE ) ); + TESTCASE( test_nodes( "Allocating a full page.", 2, + 0 ) ); + + /* Allocating *almost* a full page; expecting one page allocation, no node split */ + TESTCASE( MEMTEST( ptr4, EFFECTIVE - 4 ) ); + TESTCASE( test_nodes( "Allocating *almost* a full page.", 3, + 0 ) ); + + /* Freeing and re-allocating the "almost" full page; expecting no page allocation, no node split */ + free( ptr4 ); + TESTCASE( MEMTEST( ptr5, EFFECTIVE - 4 ) ); + TESTCASE( ptr4 == ptr5 ); + TESTCASE( test_nodes( "Freeing and re-allocating the \"almost\" full page.", 3 ) ); + + /* Freeing the full page from test #3; expecting a full-sized free node. */ + free( ptr3 ); + TESTCASE( test_nodes( "Freeing the full page from test #3.", 3, + _PDCLIB_PAGESIZE * 1, EFFECTIVE, + 0 ) ); + + /* Allocating two full pages; expecting two page allocations, no node split */ + TESTCASE( MEMTEST( ptr3, EFFECTIVE + _PDCLIB_PAGESIZE ) ); + TESTCASE( test_nodes( "Allocating two full pages.", 5, + _PDCLIB_PAGESIZE * 1, EFFECTIVE, + 0 ) ); + + /* Re-allocating to size of 10 bytes; expecting no page allocation, no node split */ + /* TODO: Shouldn't realloc() split the now much-too-large node? */ + TESTCASE( realloc( ptr3, 10 ) == ptr3 ); + TESTCASE( test_nodes( "Re-allocating to size of 10 bytes.", 5, + _PDCLIB_PAGESIZE * 1, EFFECTIVE, + 0 ) ); + + /* Re-allocating to size of two full pages; expecting no page allocation, no node split */ + TESTCASE( realloc( ptr3, EFFECTIVE + _PDCLIB_PAGESIZE ) == ptr3 ); + TESTCASE( test_nodes( "Re-allocating to size of two full pages.", 5, + _PDCLIB_PAGESIZE * 1, EFFECTIVE, + 0 ) ); + + /* Re-allocating to size of three full pages; expecting three page allocation, freeing of two-page node */ + TESTCASE( realloc( ptr3, EFFECTIVE + _PDCLIB_PAGESIZE * 2 ) != ptr3 ); + TESTCASE( test_nodes( "Re-allocating to size of three full pages.", 8, + _PDCLIB_PAGESIZE * 1, EFFECTIVE, + _PDCLIB_PAGESIZE * 3, EFFECTIVE + _PDCLIB_PAGESIZE, + 0 ) ); + + /* Allocating two full pages; expecting allocation of the available two-page node */ + TESTCASE( MEMTEST( ptr4, EFFECTIVE + _PDCLIB_PAGESIZE ) ); + TESTCASE( test_nodes( "Allocating two full pages.", 8, + _PDCLIB_PAGESIZE * 1, EFFECTIVE, + 0 ) ); + + /* Allocating zero bytes; expecting no change */ + TESTCASE( ! MEMTEST( ptr6, 0 ) ); + TESTCASE( test_nodes( "Allocating zero bytes.", 8, + _PDCLIB_PAGESIZE * 1, EFFECTIVE, + 0 ) ); + + /* Allocating 4 bytes; expecting upsizing of requestupsizing of size, node split */ + TESTCASE( MEMTEST( ptr7, 4 ) ); + TESTCASE( test_nodes( "Allocating 4 bytes.", 8, + _PDCLIB_PAGESIZE * 1 + _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ), + EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ), + 0 ) ); + + /* Allocating the rest of the page; expecting no page allocation and assignment of the remaining node */ + TESTCASE( MEMTEST( ptr8, EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ) ) ); + TESTCASE( test_nodes( "Allocating the rest of the page.", 8, 0 ) ); + + /* Freeing the node from the previous test; expecting node to re-appear in free list */ + free( ptr8 ); + TESTCASE( test_nodes( "Freeing the node from the previous test.", 8, + _PDCLIB_PAGESIZE * 1 + _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ), + EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ), + 0 ) ); + + /* Allocating one byte more than available in free node; expecting page allocation */ + TESTCASE( MEMTEST( ptr8, EFFECTIVE + 1 - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ) ) ); + TESTCASE( test_nodes( "Allocating one byte more than available in free node.", 9, + _PDCLIB_PAGESIZE * 1 + _PDCLIB_MINALLOC + sizeof( struct _PDCLIB_memnode_t ), + EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ), + 0 ) ); + + /* Re-allocating with NULL pointer; expecting no page allocation, no node split */ + ptr9 = realloc( NULL, EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ) ); + TESTCASE( ptr9 != NULL ); + TESTCASE( memset( ptr9, 0, EFFECTIVE - _PDCLIB_MINALLOC - sizeof( struct _PDCLIB_memnode_t ) ) == ptr9 ); + TESTCASE( test_nodes( "Re-allocating with NULL pointer.", 9, 0 ) ); + + /* Allocating a bit more than half a page; expecting page allocation, node split */ +#define TESTSIZE 3000 + TESTCASE( MEMTEST( ptrA, TESTSIZE ) ); + TESTCASE( test_nodes( "Allocating a bit more than half a page.", 10, + _PDCLIB_PAGESIZE * 9 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + 0 ) ); + + /* Allocating a bit more than half a page; expecting page allocation, node split */ + TESTCASE( MEMTEST( ptrB, TESTSIZE ) ); + TESTCASE( test_nodes( "Allocating a bit more than half a page.", 11, + _PDCLIB_PAGESIZE * 9 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + _PDCLIB_PAGESIZE * 10 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + 0 ) ); + + /* Allocating a bit more than half a page; expecting page allocation, node split */ + TESTCASE( MEMTEST( ptrC, TESTSIZE ) ); + TESTCASE( test_nodes( "Allocating a bit more than half a page.", 12, + _PDCLIB_PAGESIZE * 9 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + _PDCLIB_PAGESIZE * 10 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + _PDCLIB_PAGESIZE * 11 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + 0 ) ); + + /* Freeing the middle node */ + free( ptrB ); + TESTCASE( test_nodes( "Freeing the middle node.", 12, + _PDCLIB_PAGESIZE * 9 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + _PDCLIB_PAGESIZE * 10 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + _PDCLIB_PAGESIZE * 11 + sizeof( struct _PDCLIB_memnode_t ) + TESTSIZE, + EFFECTIVE - sizeof( struct _PDCLIB_memnode_t ) - TESTSIZE, + _PDCLIB_PAGESIZE * 10, + TESTSIZE, + 0 ) ); + +#else + puts( " NOTEST malloc() test driver is PDCLib-specific." ); +#endif + return TEST_RESULTS; +} + +#endif diff --git a/opt/malloc-solar/realloc.c b/opt/malloc-solar/realloc.c new file mode 100644 index 0000000..099ad5d --- /dev/null +++ b/opt/malloc-solar/realloc.c @@ -0,0 +1,58 @@ +/* $Id$ */ + +/* void * realloc( void *, size_t ) + + This file is part of the Public Domain C Library (PDCLib). + Permission is granted to use, modify, and / or redistribute at will. +*/ + +#include +#include +#include + +#ifndef REGTEST + +/* TODO: Primitive placeholder. Improve. */ + +void * realloc( void * ptr, size_t size ) +{ + void * newptr = NULL; + if ( ptr == NULL ) + { + return malloc( size ); + } + if ( size > 0 ) + { + struct _PDCLIB_memnode_t * baseptr = (struct _PDCLIB_memnode_t *)( (char *)ptr - sizeof( struct _PDCLIB_memnode_t ) ); + if ( baseptr->size >= size ) + { + /* Current memnode is large enough; nothing to do. */ + return ptr; + } + else + { + /* Get larger memnode and copy over contents. */ + if ( ( newptr = malloc( size ) ) == NULL ) + { + return NULL; + } + memcpy( newptr, ptr, baseptr->size ); + } + } + free( ptr ); + return newptr; +} + +#endif + +#ifdef TEST +#include <_PDCLIB_test.h> + +int main( void ) +{ + /* tests covered in malloc test driver */ + return TEST_RESULTS; +} + +#endif + diff --git a/opt/nothread/_PDCLIB_threadconfig.h b/opt/nothread/_PDCLIB_threadconfig.h new file mode 100644 index 0000000..39478e9 --- /dev/null +++ b/opt/nothread/_PDCLIB_threadconfig.h @@ -0,0 +1,24 @@ +#ifndef _PDCLIB_THREADCONFIG_H +#define _PDCLIB_THREADCONFIG_H +#include <_PDCLIB_aux.h> +#include <_PDCLIB_config.h> + +_PDCLIB_BEGIN_EXTERN_C +#define _PDCLIB_ONCE_FLAG_INIT 0 +#define _PDCLIB_ONCE_FLAG_DONE 1 +typedef char _PDCLIB_once_flag; + +void _PDCLIB_call_once(_PDCLIB_once_flag *flag, void (*func)(void)); + +#define _PDCLIB_THRD_HAVE_MISC +#define _PDCLIB_CND_T char +#define _PDCLIB_MTX_T char +#define _PDCLIB_TSS_T struct _PDCLIB_tss + +struct _PDCLIB_tss { + struct _PDCLIB_tss *self; + void *value; +}; + +_PDCLIB_END_EXTERN_C +#endif diff --git a/opt/nothread/call_once.c b/opt/nothread/call_once.c new file mode 100644 index 0000000..06de779 --- /dev/null +++ b/opt/nothread/call_once.c @@ -0,0 +1,9 @@ +#include + +void _PDCLIB_call_once(_PDCLIB_once_flag *flag, void (*func)(void)) +{ + if(*flag != _PDCLIB_ONCE_FLAG_DONE) { + func(); + *flag = _PDCLIB_ONCE_FLAG_DONE; + } +} \ No newline at end of file diff --git a/opt/nothread/cnd_init.c b/opt/nothread/cnd_init.c new file mode 100644 index 0000000..1683691 --- /dev/null +++ b/opt/nothread/cnd_init.c @@ -0,0 +1,7 @@ +#include + +int cnd_init(cnd_t *cond) +{ + /* does nothing */ + return thrd_success; +} diff --git a/opt/nothread/cnd_signal.c b/opt/nothread/cnd_signal.c new file mode 100644 index 0000000..ca6a789 --- /dev/null +++ b/opt/nothread/cnd_signal.c @@ -0,0 +1,6 @@ +#include + +int cnd_signal(cnd_t *cond) +{ + return thrd_success; +} \ No newline at end of file diff --git a/opt/nothread/cnd_wait.c b/opt/nothread/cnd_wait.c new file mode 100644 index 0000000..2948d4f --- /dev/null +++ b/opt/nothread/cnd_wait.c @@ -0,0 +1,6 @@ +#include + +int cnd_wait(cnd_t *cond, mtx_t *mtx) +{ + return thrd_error; +} \ No newline at end of file diff --git a/opt/nothread/config.mk b/opt/nothread/config.mk new file mode 100644 index 0000000..e69de29 diff --git a/opt/nothread/mtx_destroy.c b/opt/nothread/mtx_destroy.c new file mode 100644 index 0000000..d9aa748 --- /dev/null +++ b/opt/nothread/mtx_destroy.c @@ -0,0 +1,4 @@ +#include + +void mtx_destroy(mtx_t *mtx) +{} diff --git a/opt/nothread/mtx_init.c b/opt/nothread/mtx_init.c new file mode 100644 index 0000000..ff506e9 --- /dev/null +++ b/opt/nothread/mtx_init.c @@ -0,0 +1,7 @@ +#include + +int mtx_init(mtx_t *mtx, int type) +{ + *mtx = 0; + return thrd_success; +} diff --git a/opt/nothread/mtx_lock.c b/opt/nothread/mtx_lock.c new file mode 100644 index 0000000..0a1afbd --- /dev/null +++ b/opt/nothread/mtx_lock.c @@ -0,0 +1,10 @@ +#include +#include + +int mtx_lock(mtx_t *mtx) +{ + if(*mtx == 0) { + *mtx = 1; + return thrd_success; + } else return thrd_error; +} \ No newline at end of file diff --git a/opt/nothread/mtx_timedlock.c b/opt/nothread/mtx_timedlock.c new file mode 100644 index 0000000..b8166b5 --- /dev/null +++ b/opt/nothread/mtx_timedlock.c @@ -0,0 +1,6 @@ +#include + +int mtx_timedlock(mtx_t *restrict mtx, const struct timespec *restrict ts) +{ + return mtx_lock(mtx); +} \ No newline at end of file diff --git a/opt/nothread/mtx_trylock.c b/opt/nothread/mtx_trylock.c new file mode 100644 index 0000000..ae32757 --- /dev/null +++ b/opt/nothread/mtx_trylock.c @@ -0,0 +1,11 @@ +#include + +int mtx_trylock(mtx_t *mtx) +{ + if(*mtx) { + return thrd_error; + } else { + *mtx = 1; + return thrd_success; + } +} diff --git a/opt/nothread/mtx_unlock.c b/opt/nothread/mtx_unlock.c new file mode 100644 index 0000000..02244bb --- /dev/null +++ b/opt/nothread/mtx_unlock.c @@ -0,0 +1,9 @@ +#include + +int mtx_unlock(mtx_t *mtx) +{ + if(*mtx) { + *mtx = 0; + return thrd_success; + } else return thrd_error; +} \ No newline at end of file diff --git a/opt/nothread/thrd_yield.c b/opt/nothread/thrd_yield.c new file mode 100644 index 0000000..8c7863f --- /dev/null +++ b/opt/nothread/thrd_yield.c @@ -0,0 +1,6 @@ +#include + +void thrd_yield(void) +{ + /* does nothing */ +} \ No newline at end of file diff --git a/opt/nothread/tss_create.c b/opt/nothread/tss_create.c new file mode 100644 index 0000000..4b8ce16 --- /dev/null +++ b/opt/nothread/tss_create.c @@ -0,0 +1,8 @@ +#include + +int tss_create(tss_t *key, tss_dtor_t dtor) +{ + key->self = key; + key->value = NULL; + return thrd_success; +} \ No newline at end of file diff --git a/opt/nothread/tss_delete.c b/opt/nothread/tss_delete.c new file mode 100644 index 0000000..fbaae7e --- /dev/null +++ b/opt/nothread/tss_delete.c @@ -0,0 +1,6 @@ +#include + +void tss_delete(tss_t key) +{ + key.self->self = NULL; +} diff --git a/opt/nothread/tss_get.c b/opt/nothread/tss_get.c new file mode 100644 index 0000000..7077ac6 --- /dev/null +++ b/opt/nothread/tss_get.c @@ -0,0 +1,6 @@ +#include + +void *tss_get(tss_t key) +{ + return key.value; +} \ No newline at end of file diff --git a/opt/nothread/tss_set.c b/opt/nothread/tss_set.c new file mode 100644 index 0000000..feea85d --- /dev/null +++ b/opt/nothread/tss_set.c @@ -0,0 +1,7 @@ +#include + +int tss_set(tss_t key, void *val) +{ + key.self->value = val; + return thrd_success; +} \ No newline at end of file -- 2.40.0