Merge branch 'master' of git://git.lumiera.org/LUMIERA

Conflicts:

	tests/Makefile.am
This commit is contained in:
Michael Ploujnikov 2008-09-06 20:15:05 -04:00
commit f5387d8bf3
77 changed files with 5355 additions and 1621 deletions

2
.gitignore vendored
View file

@ -17,3 +17,5 @@ configure
config.log
aclocal.m4
semantic.cache
wiki/backups/*
doc/devel/draw/*.png

View file

@ -46,6 +46,9 @@ include $(top_srcdir)/src/common/Makefile.am
include $(top_srcdir)/src/lib/Makefile.am
include $(top_srcdir)/src/backend/Makefile.am
# tools
include $(top_srcdir)/src/tool/Makefile.am
# gui
include $(top_srcdir)/src/gui/Makefile.am

View file

@ -79,7 +79,7 @@ def setupBasicEnvironment():
env.Append(CPPDEFINES = '_GNU_SOURCE')
appendCppDefine(env,'DEBUG','DEBUG', 'NDEBUG')
appendCppDefine(env,'OPENGL','USE_OPENGL')
# appendCppDefine(env,'OPENGL','USE_OPENGL')
appendVal(env,'ARCHFLAGS', 'CCFLAGS') # for both C and C++
appendVal(env,'OPTIMIZE', 'CCFLAGS', val=' -O3')
appendVal(env,'DEBUG', 'CCFLAGS', val=' -ggdb')
@ -128,7 +128,7 @@ def defineCmdlineOptions():
allowed_values=('ALPHA', 'BETA', 'RELEASE'))
,BoolOption('DEBUG', 'Build with debugging information and no optimizations', False)
,BoolOption('OPTIMIZE', 'Build with strong optimization (-O3)', False)
,BoolOption('OPENGL', 'Include support for OpenGL preview rendering', False)
# ,BoolOption('OPENGL', 'Include support for OpenGL preview rendering', False)
# ,EnumOption('DIST_TARGET', 'Build target architecture', 'auto',
# allowed_values=('auto', 'i386', 'i686', 'x86_64' ), ignorecase=2)
,PathOption('DESTDIR', 'Installation dir prefix', '/usr/local')
@ -337,8 +337,8 @@ def definePostBuildTargets(env, artifacts):
env.Clean ('build', [ '$SRCDIR/pre.gch' ])
doxydoc = artifacts['doxydoc'] = env.Doxygen('doc/devel/Doxyfile')
env.Alias ('doxydoc', doxydoc)
env.Clean ('doxydoc', doxydoc + ['doc/devel/,doxylog','doc/devel/warnings.txt'])
env.Alias ('doc', doxydoc)
env.Clean ('doc', doxydoc + ['doc/devel/,doxylog','doc/devel/warnings.txt'])
def defineInstallTargets(env, artifacts):

View file

@ -1,11 +1,11 @@
# Doxyfile 1.5.5
# Doxyfile 1.5.6
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = Lumiera
PROJECT_NUMBER = 0.1+pre
PROJECT_NUMBER = 3.0+alpha
OUTPUT_DIRECTORY =
CREATE_SUBDIRS = YES
OUTPUT_LANGUAGE = English
@ -32,7 +32,7 @@ SHORT_NAMES = NO
JAVADOC_AUTOBRIEF = YES
QT_AUTOBRIEF = NO
MULTILINE_CPP_IS_BRIEF = NO
DETAILS_AT_TOP = YES
DETAILS_AT_TOP = NO
INHERIT_DOCS = YES
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 4
@ -44,6 +44,7 @@ OPTIMIZE_OUTPUT_VHDL = NO
BUILTIN_STL_SUPPORT = YES
CPP_CLI_SUPPORT = NO
SIP_SUPPORT = NO
IDL_PROPERTY_SUPPORT = YES
DISTRIBUTE_GROUP_DOC = NO
SUBGROUPING = YES
TYPEDEF_HIDES_STRUCT = NO
@ -65,8 +66,8 @@ CASE_SENSE_NAMES = YES
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = YES
INLINE_INFO = YES
SORT_MEMBER_DOCS = NO
SORT_BRIEF_DOCS = NO
SORT_MEMBER_DOCS = YES
SORT_BRIEF_DOCS = YES
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = NO
GENERATE_TODOLIST = YES
@ -77,6 +78,8 @@ ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
SHOW_DIRECTORIES = NO
SHOW_FILES = YES
SHOW_NAMESPACES = YES
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
@ -87,7 +90,7 @@ WARN_IF_UNDOCUMENTED = NO
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = YES
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE = warnings.txt
WARN_LOGFILE =
#---------------------------------------------------------------------------
# configuration options related to the input files
#---------------------------------------------------------------------------
@ -179,18 +182,20 @@ HTML_STYLESHEET =
HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
GENERATE_DOCSET = NO
DOCSET_FEEDNAME = "Lumiera Doxygen docs"
DOCSET_FEEDNAME = "Doxygen generated docs"
DOCSET_BUNDLE_ID = org.doxygen.Project
HTML_DYNAMIC_SECTIONS = NO
CHM_FILE =
HHC_LOCATION =
GENERATE_CHI = NO
CHM_INDEX_ENCODING =
BINARY_TOC = NO
TOC_EXPAND = NO
DISABLE_INDEX = NO
ENUM_VALUES_PER_LINE = 4
GENERATE_TREEVIEW = YES
TREEVIEW_WIDTH = 250
FORMULA_FONTSIZE = 10
#---------------------------------------------------------------------------
# configuration options related to the LaTeX output
#---------------------------------------------------------------------------
@ -268,6 +273,8 @@ CLASS_DIAGRAMS = YES
MSCGEN_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = YES
DOT_FONTNAME = FreeSans
DOT_FONTPATH =
CLASS_GRAPH = YES
COLLABORATION_GRAPH = YES
GROUP_GRAPHS = YES

View file

@ -14,10 +14,10 @@
sodipodi:version="0.32"
inkscape:version="0.45.1"
version="1.0"
sodipodi:docbase="/home/hiv/devel/skizzen"
sodipodi:docname="Cin3.Architecture-1.svg"
sodipodi:docbase="/mnt/Lager/heim/devel/lumi/doc/devel/draw"
sodipodi:docname="Lumi.Architecture-1.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
inkscape:export-filename="/home/hiv/devel/skizzen/Cin3.Architecture-1.png"
inkscape:export-filename="/home/hiv/devel/skizzen/Lumi.Architecture-1.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
@ -43,17 +43,24 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1"
inkscape:cx="394.65714"
inkscape:cy="258.89573"
inkscape:zoom="1.4811321"
inkscape:cx="384"
inkscape:cy="265"
inkscape:document-units="px"
inkscape:current-layer="layer1"
width="768px"
height="530px"
inkscape:window-width="1010"
inkscape:window-height="812"
inkscape:window-width="1209"
inkscape:window-height="949"
inkscape:window-x="0"
inkscape:window-y="0" />
inkscape:window-y="28"
showgrid="true"
inkscape:grid-points="true"
inkscape:grid-bbox="false"
gridspacingx="2px"
gridspacingy="2px"
objecttolerance="50"
gridtolerance="10000" />
<metadata
id="metadata7">
<rdf:RDF>
@ -87,7 +94,7 @@
style="opacity:1;color:#000000;fill:#ececec;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3136"
width="449.55356"
height="142.91072"
height="144.89977"
x="46.375008"
y="369.10715" />
<rect
@ -269,15 +276,19 @@
y="252.75615" />
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr;text-anchor:start;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
x="602.52142"
y="267.42578"
id="text3229"
sodipodi:linespacing="100%"><tspan
y="267.42578"
sodipodi:role="line"
id="tspan2336"
x="602.52142"
id="tspan3233"
sodipodi:role="line">Defaults</tspan></text>
y="267.42578">Session</tspan><tspan
sodipodi:role="line"
id="tspan2338"
x="602.52142"
y="277.42578">Defaults</tspan></text>
<rect
y="46.375"
x="606.66071"
@ -286,10 +297,10 @@
id="rect3235"
style="opacity:1;color:#000000;fill:#ececec;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<rect
y="393.71426"
x="166.57144"
height="75.714287"
width="103.16072"
y="389.97562"
x="159.97351"
height="79.452911"
width="119.98783"
id="rect3246"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<text
@ -304,12 +315,12 @@
x="174.14285"
y="455.23215">Cache</tspan></text>
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3254"
width="203.48215"
height="32.178574"
x="166.57141"
y="475.10712" />
width="119.99424"
height="29.96665"
x="159.96713"
y="480.03333" />
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
@ -322,10 +333,10 @@
x="174.14285"
y="494.98215">IO-Handling</tspan></text>
<rect
y="454.28571"
x="373.83926"
height="53.000004"
width="113.57143"
y="455.99066"
x="290"
height="54.009354"
width="200.02533"
id="rect3263"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<rect
@ -333,92 +344,92 @@
id="rect3268"
width="17.035713"
height="17.982149"
x="285.82141"
x="532.60168"
y="393.71426" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3270"
width="17.035713"
height="17.982149"
x="313.03125"
x="559.81152"
y="393.71426" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3272"
width="17.035713"
height="17.982149"
x="340.24106"
x="587.0213"
y="393.71426" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3274"
width="17.035713"
height="17.982149"
x="367.4509"
x="614.23114"
y="393.71426" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3276"
width="17.035713"
height="17.982149"
x="394.66074"
x="641.44098"
y="393.71426" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3278"
width="17.035713"
height="17.982149"
x="285.82141"
x="532.60168"
y="428.25894" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3280"
width="17.035713"
height="17.982149"
x="313.03125"
x="559.81152"
y="428.25894" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3282"
width="17.035713"
height="17.982149"
x="340.24106"
x="587.0213"
y="428.25894" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3284"
width="17.035713"
height="17.982149"
x="367.4509"
x="614.23114"
y="428.25894" />
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000024;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect3286"
width="17.035713"
height="17.982149"
x="394.66074"
x="641.44098"
y="428.25894" />
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
x="381.06494"
y="472.18738"
x="300"
y="480"
id="text3306"
sodipodi:linespacing="100%"><tspan
sodipodi:role="line"
id="tspan3310"
x="381.06494"
y="472.18738">Storage Backend(s)</tspan></text>
x="300"
y="480">Storage Backend(s)</tspan></text>
<text
sodipodi:linespacing="100%"
id="text3312"
y="422.02664"
x="280.74353"
x="527.5238"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
sodipodi:role="line"
id="tspan3316"
x="280.74353"
x="527.5238"
y="422.02664">Plugins (Codecs, Effects,...)</tspan></text>
<g
id="g3318"
@ -538,7 +549,7 @@
sodipodi:role="line"
id="tspan6303"
x="523.375"
y="355.89285"></tspan></text>
y="355.89285" /></text>
<text
xml:space="preserve"
style="font-size:18px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;color:#000000;fill:#cccccc;fill-opacity:1;fill-rule:evenodd;stroke:#333333;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
@ -553,11 +564,11 @@
sodipodi:role="line"
id="tspan6323"
x="383.30356"
y="214.85713"></tspan><tspan
y="214.85713" /><tspan
sodipodi:role="line"
id="tspan6325"
x="383.30356"
y="232.85713"></tspan></text>
y="232.85713" /></text>
<g
id="g8843">
<path
@ -584,20 +595,6 @@
d="M 83.995536,360.5893 L 86.125001,343.08037 L 79.500001,343.54113 L 83.995536,360.5893 z "
style="color:#000000;fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
<g
transform="matrix(-0.6256902,0.7800716,0.7800716,0.6256902,147.19486,107.67292)"
id="g8855">
<path
sodipodi:nodetypes="ccc"
style="fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 80.911116,238.23155 L 83.28125,354.90625 L 80.911116,238.23155 z "
id="path8857" />
<path
style="color:#000000;fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 83.995536,360.5893 L 86.125001,343.08037 L 79.500001,343.54113 L 83.995536,360.5893 z "
id="path8859"
sodipodi:nodetypes="cccc" />
</g>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;opacity:1;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
@ -779,5 +776,106 @@
id="tspan14759"
x="243.81104"
y="292.75879">(re)-Building</tspan></text>
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2288"
width="80.071442"
height="60.065418"
x="409.92859"
y="390" />
<text
sodipodi:linespacing="100%"
id="text2290"
y="410.04694"
x="414.28015"
style="font-size:10.00114441px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
xml:space="preserve"
transform="scale(1.0001145,0.9998856)"><tspan
sodipodi:role="line"
id="tspan2294"
x="414.28015"
y="410.04694"
style="stroke-width:1">Plugin Loader</tspan></text>
<rect
y="390"
x="350.2843"
height="60.065418"
width="49.715698"
id="rect2296"
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
<g
transform="matrix(-0.6256902,0.7800716,0.7800716,0.6256902,201.26971,137.82439)"
id="g8855">
<path
sodipodi:nodetypes="ccc"
style="fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 80.335451,191.0022 L 83.28125,354.90625 L 80.335451,191.0022 z "
id="path8857" />
<path
style="color:#000000;fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 83.995536,360.5893 L 86.125001,343.08037 L 79.500001,343.54113 L 83.995536,360.5893 z "
id="path8859"
sodipodi:nodetypes="cccc" />
</g>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
x="352.10049"
y="410"
id="text2298"
sodipodi:linespacing="100%"><tspan
sodipodi:role="line"
id="tspan2302"
x="352.10049"
y="410">Serializer</tspan></text>
<g
id="g2304"
transform="matrix(-0.6256902,0.7800716,0.7800716,0.6256902,321.26971,197.82439)" />
<g
id="g2310"
transform="matrix(2.2113858e-2,0.9997554,0.9997554,-2.2113858e-2,160.03746,354.11646)">
<path
id="path2312"
d="M 82.05604,278.21602 L 83.28125,354.90625 L 82.05604,278.21602 z "
style="fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
sodipodi:nodetypes="ccc" />
<path
sodipodi:nodetypes="cccc"
id="path2314"
d="M 83.995536,360.5893 L 86.125001,343.08037 L 79.500001,343.54113 L 83.995536,360.5893 z "
style="color:#000000;fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
</g>
<rect
style="color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1.00000012;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="rect2324"
width="50.0009"
height="60.065418"
x="290"
y="390" />
<text
sodipodi:linespacing="100%"
id="text2326"
y="410"
x="295.16116"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:100%;writing-mode:lr-tb;text-anchor:start;color:#000000;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Bitstream Vera Sans"
xml:space="preserve"><tspan
sodipodi:role="line"
id="tspan2328"
x="295.16116"
y="410">Defaults</tspan></text>
<g
transform="matrix(0.6256902,0.7800716,-0.7800716,0.6256902,438.73029,137.82439)"
id="g2330">
<path
sodipodi:nodetypes="ccc"
style="fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 80.911116,238.23155 L 83.28125,354.90625 L 80.911116,238.23155 z "
id="path2332" />
<path
style="color:#000000;fill:#00e800;fill-opacity:0.75;fill-rule:evenodd;stroke:#00ff00;stroke-width:2;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
d="M 83.995536,360.5893 L 86.125001,343.08037 L 79.500001,343.54113 L 83.995536,360.5893 z "
id="path2334"
sodipodi:nodetypes="cccc" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 58 KiB

118
doc/devel/draw/LumiLogo.svg Normal file
View file

@ -0,0 +1,118 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://web.resource.org/cc/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="100"
height="100"
id="svg2676"
sodipodi:version="0.32"
inkscape:version="0.45.1"
version="1.0"
sodipodi:docbase="/mnt/Lager/heim/devel/lumi/doc/devel/draw"
sodipodi:docname="LumiLogo.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape"
inkscape:export-filename="/mnt/Lager/heim/devel/lumi/doc/devel/draw/LumiLogo32.png"
inkscape:export-xdpi="57.310001"
inkscape:export-ydpi="57.310001">
<defs
id="defs2678">
<linearGradient
id="linearGradient11428">
<stop
offset="0"
style="stop-color:#eed98e;stop-opacity:1;"
id="stop11430" />
<stop
offset="1"
style="stop-color:#553163;stop-opacity:1;"
id="stop11432" />
</linearGradient>
<linearGradient
id="linearGradient11549"
gradientUnits="userSpaceOnUse"
inkscape:collect="always"
x1="50.468533"
y1="46.267605"
xlink:href="#linearGradient11428"
gradientTransform="matrix(2.0887729,0,0,2.0886777,-60.313318,-60.306023)"
x2="64.260468"
y2="68.541466" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="8"
inkscape:cx="77.291306"
inkscape:cy="36.924563"
inkscape:document-units="px"
inkscape:current-layer="svg2676"
width="100px"
height="100px"
inkscape:window-width="1179"
inkscape:window-height="918"
inkscape:window-x="365"
inkscape:window-y="25" />
<metadata
id="metadata2681">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title>Lumiera Logo</dc:title>
<dc:date>8/2008</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Lumiera.org</dc:title>
</cc:Agent>
</dc:creator>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/2.5/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/2.5/">
<cc:permits
rdf:resource="http://web.resource.org/cc/Reproduction" />
<cc:permits
rdf:resource="http://web.resource.org/cc/Distribution" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Notice" />
<cc:requires
rdf:resource="http://web.resource.org/cc/Attribution" />
<cc:permits
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
<cc:requires
rdf:resource="http://web.resource.org/cc/ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:label="LumiLogo"
inkscape:groupmode="layer"
id="lay_Logo"
inkscape:export-filename="/mnt/Lager/heim/devel/lumi/doc/devel/draw/LumiLogo.png"
inkscape:export-xdpi="114.62687"
inkscape:export-ydpi="114.62687">
<g
style="opacity:1;color:#000000;fill:#951616;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient11549);stroke-width:0.5;stroke-linecap:round;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
id="g_LumiLogo"
transform="matrix(0.5,0,0,0.5,30,30)">
<path
id="LumieraLogo"
sodipodi:nodetypes="ccccccccccccscsssccsccscsssccccsssc"
d="M 0,11.48771 L 0,88.512258 C 0,94.876459 5.12376,100.00587 11.488252,99.999984 L 88.511753,99.999984 C 94.876244,99.999984 100,94.876455 100,88.512258 L 100,11.492269 C 100,5.1280689 94.876244,-1.6079329e-05 88.511753,-1.6079329e-05 L 11.488252,-1.6079329e-05 C 5.6951387,-1.6079329e-05 0,5.5258281 0,11.48771 z M 21.148826,0.26562719 C 29.955201,0.26562719 42.558748,6.0632763 42.558748,35.120436 L 42.558748,77.024531 C 42.558748,87.851217 43.097639,96.997511 50.065277,96.997511 C 52.34862,96.997511 53.64308,95.484552 54.047,94.908832 C 49.700804,94.769736 46.214101,91.194803 46.214101,86.815208 C 46.214101,82.347527 49.840211,78.721581 54.308096,78.721581 C 58.775981,78.721581 62.402092,82.347527 62.402092,86.815208 C 62.402092,88.437921 61.919927,89.921159 61.096608,91.188377 C 61.096608,91.188377 61.031334,91.318919 61.031334,91.318919 C 58.08739,95.518358 54.965657,99.738901 47.519584,99.738901 C 38.713208,99.738901 26.109662,93.941251 26.109662,64.884092 L 26.109662,22.979996 C 26.109662,12.15331 25.57077,3.0070164 18.603134,3.0070164 C 16.319793,3.0070164 15.025331,4.5199752 14.62141,5.0956943 C 18.967606,5.2347913 22.454309,8.8097247 22.454309,13.189319 C 22.454309,17.657001 18.828199,21.282945 14.360314,21.282945 C 9.892429,21.282945 6.2663188,17.657001 6.2663188,13.189319 C 6.2663188,11.566604 6.7484827,10.083368 7.5718019,8.8161505 C 7.5718019,8.8161505 7.6370761,8.6856087 7.6370761,8.6856087 C 10.58102,4.4861692 13.702754,0.26562719 21.148826,0.26562719 z M 75.456921,18.280472 C 79.924808,18.280472 83.550918,21.906416 83.550918,26.374097 C 83.550918,30.841779 79.924808,34.467725 75.456921,34.467725 C 70.989037,34.467725 67.362928,30.841779 67.362928,26.374097 C 67.362928,21.906416 70.989037,18.280472 75.456921,18.280472 z " />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 5.8 KiB

View file

@ -26,7 +26,12 @@ liblumibackend_a_SOURCES = \
$(liblumibackend_a_srcdir)/file.c \
$(liblumibackend_a_srcdir)/filehandle.c \
$(liblumibackend_a_srcdir)/filedescriptor.c \
$(liblumibackend_a_srcdir)/filehandlecache.c
$(liblumibackend_a_srcdir)/filehandlecache.c \
$(liblumibackend_a_srcdir)/config.c \
$(liblumibackend_a_srcdir)/config_typed.c \
$(liblumibackend_a_srcdir)/configentry.c \
$(liblumibackend_a_srcdir)/configitem.c \
$(liblumibackend_a_srcdir)/config_lookup.c
noinst_HEADERS += \
@ -35,5 +40,9 @@ noinst_HEADERS += \
$(liblumibackend_a_srcdir)/file.h \
$(liblumibackend_a_srcdir)/filehandle.h \
$(liblumibackend_a_srcdir)/filedescriptor.h \
$(liblumibackend_a_srcdir)/filehandlecache.h
$(liblumibackend_a_srcdir)/filehandlecache.h \
$(liblumibackend_a_srcdir)/config.h \
$(liblumibackend_a_srcdir)/configentry.h \
$(liblumibackend_a_srcdir)/configitem.h \
$(liblumibackend_a_srcdir)/config_lookup.h

355
src/backend/config.c Normal file
View file

@ -0,0 +1,355 @@
/*
config.c - Lumiera configuration system
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
//TODO: Support library includes//
#include "lib/safeclib.h"
//TODO: Lumiera header includes//
#include "backend/config.h"
//TODO: internal/static forward declarations//
//TODO: System includes//
#include <stdint.h>
#include <stdlib.h>
#include <ctype.h>
/**
* @file
*
*/
NOBUG_DEFINE_FLAG_PARENT (config_all, backend);
NOBUG_DEFINE_FLAG_PARENT (config, config_all);
NOBUG_DEFINE_FLAG_PARENT (config_typed, config_all);
NOBUG_DEFINE_FLAG_PARENT (config_file, config_all);
NOBUG_DEFINE_FLAG_PARENT (config_item, config_all);
NOBUG_DEFINE_FLAG_PARENT (config_lookup, config_all);
LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX, "syntax error in configfile");
LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_KEY, "syntax error in key");
LUMIERA_ERROR_DEFINE (CONFIG_SYNTAX_VALUE, "syntax error in value");
LUMIERA_ERROR_DEFINE (CONFIG_NO_ENTRY, "no configuration entry");
LUMIERA_ERROR_DEFINE (CONFIG_DEFAULT, "illegal default value");
/**
* defaults for the configuraton system itself
*/
const char* lumiera_config_defaults[] =
{
/* Low level formating, don't change these */
"config.formatstr.link = '< %s'",
"config.formatstr.number.dec = '= %lld'",
"config.formatstr.number.hex = '= 0x%llX'",
"config.formatstr.number.oct = '= 0%llo'",
"config.formatstr.real = '= %Lg'",
"config.formatstr.real.dec = '= %Lf'",
"config.formatstr.real.sci = '= %Le'",
"config.formatstr.string = '=%s'",
"config.formatstr.string.dquoted = '= \"%s\"'",
"config.formatstr.string.quoted = '= ''%s'''",
"config.formatstr.word = '= %s'",
"config.formatstr.bool = '= %d'",
/* default representations per type */
"config.formatdef.link < config.formatstr.link",
"config.formatdef.number < config.formatstr.number.dec",
"config.formatdef.real < config.formatstr.real",
"config.formatdef.string < config.formatstr.string",
"config.formatdef.word < config.formatstr.word",
"config.formatdef.bool < config.formatstr.bool",
/* per key formatting override stored under */
"config.formatkey ='config.format.%s'",
NULL
};
/* singleton config */
LumieraConfig lumiera_global_config = NULL;
int
lumiera_config_init (const char* path)
{
TRACE (config);
REQUIRE (!lumiera_global_config, "Configuration subsystem already initialized");
REQUIRE (path);
NOBUG_INIT_FLAG (config_all);
NOBUG_INIT_FLAG (config);
NOBUG_INIT_FLAG (config_typed);
NOBUG_INIT_FLAG (config_file);
NOBUG_INIT_FLAG (config_item);
NOBUG_INIT_FLAG (config_lookup);
lumiera_global_config = lumiera_malloc (sizeof (*lumiera_global_config));
lumiera_config_lookup_init (&lumiera_global_config->keys);
lumiera_configitem_init (&lumiera_global_config->defaults);
lumiera_configitem_init (&lumiera_global_config->files);
lumiera_configitem_init (&lumiera_global_config->TODO_unknown);
lumiera_rwlock_init (&lumiera_global_config->lock, "config rwlock", &NOBUG_FLAG (config));
lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "config.path = %s", path));
for (const char** itr = lumiera_config_defaults; *itr; ++itr)
{
lumiera_config_setdefault (*itr);
}
return 0;
}
void
lumiera_config_destroy ()
{
TRACE (config);
if (lumiera_global_config)
{
lumiera_rwlock_destroy (&lumiera_global_config->lock, &NOBUG_FLAG (config));
lumiera_configitem_destroy (&lumiera_global_config->defaults, &lumiera_global_config->keys);
lumiera_configitem_destroy (&lumiera_global_config->files, &lumiera_global_config->keys);
lumiera_configitem_destroy (&lumiera_global_config->TODO_unknown, &lumiera_global_config->keys);
lumiera_config_lookup_destroy (&lumiera_global_config->keys);
lumiera_free (lumiera_global_config);
lumiera_global_config = NULL;
}
else
WARN (config, "Tried to destroy non initialized config subsystem");
}
int
lumiera_config_load (const char* file)
{
TRACE (config);
UNIMPLEMENTED();
return -1;
}
int
lumiera_config_save ()
{
TRACE (config);
UNIMPLEMENTED();
return -1;
}
int
lumiera_config_purge (const char* filename)
{
TRACE (config);
UNIMPLEMENTED();
return -1;
}
int
lumiera_config_get (const char* key, const char** value)
{
TRACE (config);
REQUIRE (key);
REQUIRE (value);
int ret = -1;
/* we translate the key for the env var override by making it uppercase and replace . with _,
as side effect, this also checks the key syntax */
char* tr_key = lumiera_tmpbuf_tr (key,
LUMIERA_CONFIG_KEY_CHARS,
LUMIERA_CONFIG_ENV_CHARS,
NULL);
if (tr_key)
{
char* env = lumiera_tmpbuf_snprintf (2048, "LUMIERA_%s", tr_key);
*value = getenv(env);
if (*value)
{
ret = 0;
NOTICE (config, "envvar override for config %s = %s", env, *value);
}
else
{
TODO ("follow '<' delegates?");
LumieraConfigitem item = lumiera_config_lookup_item_find (&lumiera_global_config->keys, key);
if (item)
{
*value = item->delim+1;
ret = 0;
}
else
LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY);
}
}
else
{
LUMIERA_ERROR_SET (config, CONFIG_SYNTAX_KEY);
}
return ret;
}
int
lumiera_config_get_default (const char* key, const char** value)
{
TRACE (config);
REQUIRE (key);
REQUIRE (value);
int ret = -1;
TODO ("follow '<' delegates?");
TODO ("refactor _get and get_default to iterator access (return LList or Lookupentry)");
LumieraConfigitem item = lumiera_config_lookup_item_tail_find (&lumiera_global_config->keys, key);
if (item && item->parent == &lumiera_global_config->defaults)
{
*value = item->delim+1;
ret = 0;
}
return ret;
}
int
lumiera_config_set (const char* key, const char* delim_value)
{
TRACE (config);
TODO ("if does this item already exist in a user writeable file?");
TODO (" replace delim_value");
TODO ("else");
TODO (" find matching prefix");
TODO (" find matching suffix");
TODO (" find proper prefix indentation, else use config.indent");
TODO (" create configitem with prefix/suffix removed");
// * set a value by key
// * handles internally everything as string:string key:value pair.
// * lowlevel function
// * tag file as dirty
// * set will create a new user configuration file if it does not exist yet or will append a line to the existing one in RAM. These files, tagged as 'dirty', will be only written if save() is called.
UNIMPLEMENTED();
return -1;
}
LumieraConfigitem
lumiera_config_setdefault (const char* line)
{
TRACE (config);
REQUIRE (line);
LumieraConfigitem item = NULL;
LUMIERA_WRLOCK_SECTION (config, &lumiera_global_config->lock)
{
const char* key = line;
while (*key && isspace (*key))
key++;
key = lumiera_tmpbuf_strndup (line, strspn (line, LUMIERA_CONFIG_KEY_CHARS));
if (!(item = lumiera_config_lookup_item_find (&lumiera_global_config->keys, key)) || item->parent != &lumiera_global_config->defaults)
{
item = lumiera_configitem_new (line);
if (item)
{
ENSURE (item->delim, "default must be a configentry with key=value or key<delegate syntax")
ENSURE (*item->delim == '=' || *item->delim == '<', "default must be a configentry with key=value or key<delegate syntax");
TRACE (config, "registering default: '%s'", item->line);
llist_insert_head (&lumiera_global_config->defaults.childs, &item->link);
item->parent = &lumiera_global_config->defaults;
lumiera_config_lookup_insert_default (&lumiera_global_config->keys, item);
}
}
}
return item;
}
void
lumiera_config_dump (FILE* out)
{
fprintf (out, "# registered defaults:\n");
LLIST_FOREACH (&lumiera_global_config->defaults.childs, node)
fprintf (out, "%s\n", ((LumieraConfigitem) node)->line);
fprintf (out, "# end of defaults\n\n");
#if 0 /*TODO UNIMPLEMENTED */
fprintf (out, "# files:\n");
lumiera_configitem files;
fprintf (out, "# volatiles:")
lumiera_configitem TODO_unknown;
#endif
}
int
lumiera_config_reset (const char* key)
{
TRACE (config);
UNIMPLEMENTED();
return -1;
}
int
lumiera_config_info (const char* key, const char** filename, unsigned* line)
{
TRACE (config);
UNIMPLEMENTED();
return -1;
}
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

262
src/backend/config.h Normal file
View file

@ -0,0 +1,262 @@
/*
config.h - Lumiera configuration system
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LUMIERA_CONFIG_H
#define LUMIERA_CONFIG_H
//TODO: Support library includes//
#include "lib/error.h"
#include "lib/rwlock.h"
//TODO: Forward declarations//
struct lumiera_config_struct;
/* master config subsystem debug flag */
NOBUG_DECLARE_FLAG (config_all);
/* config subsystem internals */
NOBUG_DECLARE_FLAG (config);
/* high level typed interface operations */
NOBUG_DECLARE_FLAG (config_typed);
/* file operations */
NOBUG_DECLARE_FLAG (config_file);
/* single config items */
NOBUG_DECLARE_FLAG (config_item);
/* lookup config keys */
NOBUG_DECLARE_FLAG (config_lookup);
LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX);
LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX_KEY);
LUMIERA_ERROR_DECLARE (CONFIG_SYNTAX_VALUE);
LUMIERA_ERROR_DECLARE (CONFIG_NO_ENTRY);
LUMIERA_ERROR_DECLARE (CONFIG_DEFAULT);
//TODO: Lumiera header includes//
#include "backend/config_lookup.h"
//TODO: System includes//
#include <nobug.h>
#include <stdio.h>
/**
* @file
* TODO documentation, http://www.pipapo.org/pipawiki/Lumiera/ConfigLoader
*/
#define LUMIERA_CONFIG_KEY_CHARS "abcdefghijklmnopqrstuvwxyz0123456789_."
#define LUMIERA_CONFIG_ENV_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789__"
struct lumiera_config_struct
{
lumiera_config_lookup keys;
lumiera_configitem defaults; /* registered default values */
lumiera_configitem files; /* all loaded files */
lumiera_configitem TODO_unknown; /* all values which are not part of a file and not default TODO: this will be removed when file support is finished */
/*
all access is protected with rwlock's.
We use rwlocks here since concurrent reads are likely common.
So far this is a global config lock, if this is a problem we might granularize it by locking on a file level.
config access is not planned to be transactional yet, if this is a problem we need to expose the rwlock to a config_acquire/config_release function pair
*/
lumiera_rwlock lock;
};
typedef struct lumiera_config_struct lumiera_config;
typedef lumiera_config* LumieraConfig;
/**
* Supported high level types: TODO documenting
*/
/* TODO: add here as 'LUMIERA_CONFIG_TYPE(name, ctype)' the _get/_set prototypes are declared automatically below, you still have to implement them in config.c */
#define LUMIERA_CONFIG_TYPES \
LUMIERA_CONFIG_TYPE(link, char*) \
LUMIERA_CONFIG_TYPE(number, signed long long) \
LUMIERA_CONFIG_TYPE(real, long double) \
LUMIERA_CONFIG_TYPE(string, char*) \
LUMIERA_CONFIG_TYPE(word, char*) \
LUMIERA_CONFIG_TYPE(bool, int)
// * does only initialize the variables, so that they get valid values, but does not allocate them as they will be allocated before as they are singleton.
// * lumiera_config_init (const char* searchpath) searchpath is a buildin-default, can be changed via configure and can be appended and overridden by using a flag, e.g. {{{ --config-path-append="" }}} or {{{ --config-path="" }}}
/**
* Initialize the configuration subsystem.
* @param path search path for config files.
* Must be called only once
*/
int
lumiera_config_init (const char* path);
// * frees all space allocated by the ConfigLoader.
/**
* Destroys the configuration subsystem.
* Subsequent calls are no-ops.
*/
void
lumiera_config_destroy ();
// * reads '''one''' single configuration file that will include all settings from other files.
// * does not read itself but give delegates reading. The actual reading and parsing will be done in configfile object. s.later.
/**
*
*/
int
lumiera_config_load (const char* file);
//{{{ lumiera_config_save () { LLIST_FOREACH(config_singleton.files, f) { LumieraFile file = (LumieraFile) f; if(lumiera_configfile_isdirty (file)) lumiera_configfile_save(file); } } }}}
// * saves all the changed settings to user's configuration files, but recognizes where settings came from and will write them to an appropriate named file. Example: '''changed''' values from ''/usr/local/share/lumiera/plugins/blur.conf'' will be saved into ''~/.lumiera/plugins/blur.conf''
// * finds out which files are dirty and which settings have to be written to user's config files.
// * does initiate the actual saving procedure by delegating the save to the actual configfile objects, see below.
// * empty user configuration files in RAM will be deleted from disk on write.
// * checks whether the file has changed since last read, and will print out an error if necessary instead of overriding it without notification.
/**
*
*/
int
lumiera_config_save ();
// * `lumiera_config_purge(const char* filename)` removes all configs loaded from filename
/**
*
*/
int
lumiera_config_purge (const char* filename);
/**
* Does a diagnostic dump of the whole config database
*/
void
lumiera_config_dump (FILE* out);
// * {{{ lumiera_config_get(...) }}}
// * get a value by key
// * handles internally everything as string:string key:value pair.
// * lowlevel function
// * lumiera_config_integer_get (const char* key, int *value) will return integers instead of strings and return 0 if succeeded and -1 if it failed.
/**
*
*/
int
lumiera_config_get (const char* key, const char** value);
int
lumiera_config_get_default (const char* key, const char** value);
// * {{{ lumiera_config_set(...) }}}
// * set a value by key
// * handles internally everything as string:string key:value pair.
// * lowlevel function
// * tag file as dirty
// * set will create a new user configuration file if it does not exist yet or will append a line to the existing one in RAM. These files, tagged as 'dirty', will be only written if save() is called.
/**
*
*
* @param key
* @param delim_value delimiter (= or <) followed by the value to be set
*
*/
int
lumiera_config_set (const char* key, const char* delim_value);
/**
* Installs a default value for a config key.
* Any key might have an associated default value which is used when
* no other configuration is available, this can be set once.
* Any subsequent call will be a no-op.
* @param line line with key, delimiter and value to store as default value
* @return NULL in case of an error, else a pointer to the default configitem
*/
LumieraConfigitem
lumiera_config_setdefault (const char* line);
// * {{{int lumiera_config_TYPE_get(const char* key, TYPE* value, const char* default) }}}
// High level config interface for different types.
// if default is given (!NULL) then value is set to default in case key was not found or any other error occured.
// error code is still set and -1 (fail) is returned in case of an error, but it might be cleared with no ill effects.
// NOTE: errors are persistent in our error handler, they must still be cleared, even when ignored.
// if default is given then 'KEY_NOT_FOUND' is not a error here, if default is NULL then it is
// NOTE2: default values are given as strings, the config loader remembers a given default value and checks if it got changed
// when it is _set(). Thus a default value can be supressed when set/written
/**
*
*/
#define LUMIERA_CONFIG_TYPE(name, type) \
int \
lumiera_config_##name##_get (const char* key, type* value);
LUMIERA_CONFIG_TYPES
#undef LUMIERA_CONFIG_TYPE
// * {{{ lumiera_config_TYPE_set (const char* key, TYPE*value, const char* fmt) }}}
// Highlevel interface for different types, fmt is a printf format specifier for the desired format, when NULL, defaults apply.
/**
*
*/
#define LUMIERA_CONFIG_TYPE(name, type) \
int \
lumiera_config_##name##_set (const char* key, type* value);
LUMIERA_CONFIG_TYPES
#undef LUMIERA_CONFIG_TYPE
// * {{{ lumiera_config_reset(...) }}}
// * reset a value by key to the system default values, thus removes a user's configuration line.
/**
*
*/
int
lumiera_config_reset (const char* key);
// * Find exact place of a setting.
/**
*
*/
int
lumiera_config_info (const char* key, const char** filename, unsigned* line);
#endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

239
src/backend/config_lookup.c Normal file
View file

@ -0,0 +1,239 @@
/*
config_lookup.c - Lookup functions for the config subsystem
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "lib/safeclib.h"
#include "backend/config_lookup.h"
#include "backend/config.h"
/* we only use one fatal error for now, when allocation in the config system fail, something else is pretty wrong */
LUMIERA_ERROR_DEFINE (CONFIG_LOOKUP, "config lookup failure");
/*
support functions for the splay tree
*/
static int
cmp_fn (const void* a, const void* b);
static void
delete_fn (PSplaynode node);
static const void*
key_fn (const PSplaynode node);
/**
* @file
* Implementation of the lookup of configuration keys
*/
LumieraConfigLookup
lumiera_config_lookup_init (LumieraConfigLookup self)
{
TRACE (config_lookup);
psplay_init (&self->tree, cmp_fn, key_fn, delete_fn);
return self;
}
LumieraConfigLookup
lumiera_config_lookup_destroy (LumieraConfigLookup self)
{
TRACE (config_lookup);
if (self)
psplay_destroy (&self->tree);
return self;
}
LumieraConfigLookupentry
lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item)
{
TRACE (config_lookup);
REQUIRE (self);
REQUIRE (item);
REQUIRE (item->key);
REQUIRE (item->key_size);
FIXME ("implement section prefix/suffix for the key");
const char* key = lumiera_tmpbuf_strcat3 (NULL, 0, item->key, item->key_size, NULL, 0);
LumieraConfigLookupentry entry = (LumieraConfigLookupentry)psplay_find (&self->tree, key, 100);
if (!entry)
entry = (LumieraConfigLookupentry)psplay_insert (&self->tree, &lumiera_config_lookupentry_new (key)->node, 100);
llist_insert_head (&entry->configitems, &item->lookup);
return entry;
}
LumieraConfigLookupentry
lumiera_config_lookup_insert_default (LumieraConfigLookup self, LumieraConfigitem item)
{
TRACE (config_lookup);
REQUIRE (self);
REQUIRE (item);
REQUIRE (item->key);
REQUIRE (item->key_size);
const char* key = lumiera_tmpbuf_snprintf (SIZE_MAX, "%.*s", item->key_size, item->key);
LumieraConfigLookupentry entry = (LumieraConfigLookupentry)psplay_find (&self->tree, key, 100);
if (!entry)
entry = (LumieraConfigLookupentry)psplay_insert (&self->tree, &lumiera_config_lookupentry_new (key)->node, 100);
TODO ("else check that no 'default' item already exists, that is, the tail element's parent points to the 'defaults' in config");
llist_insert_tail (&entry->configitems, &item->lookup);
return entry;
}
LumieraConfigitem
lumiera_config_lookup_remove (LumieraConfigLookup self, LumieraConfigitem item)
{
TRACE (config_lookup);
REQUIRE (!llist_is_empty (&item->lookup), "item is not in a lookup");
if (llist_is_single (&item->lookup))
{
/* last item in lookup, remove it from the splay tree */
LumieraConfigLookupentry entry = LLIST_TO_STRUCTP (llist_next (&item->lookup), lumiera_config_lookupentry, configitems);
llist_unlink (&item->lookup);
psplay_delete_node (&self->tree, (PSplaynode)entry);
}
else
{
/* more than this item present in hash, just unlink this item */
llist_unlink (&item->lookup);
}
return item;
}
LumieraConfigLookupentry
lumiera_config_lookup_find (LumieraConfigLookup self, const char* key)
{
TRACE (config_lookup);
return (LumieraConfigLookupentry)psplay_find (&self->tree, key, 100);
}
LumieraConfigitem
lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key)
{
TRACE (config_lookup);
LumieraConfigLookupentry entry =
lumiera_config_lookup_find (self, key);
if (entry && !llist_is_empty (&entry->configitems))
return LLIST_TO_STRUCTP (llist_head (&entry->configitems), lumiera_configitem, lookup);
return NULL;
}
LumieraConfigitem
lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key)
{
TRACE (config_lookup);
LumieraConfigLookupentry entry =
lumiera_config_lookup_find (self, key);
if (entry && !llist_is_empty (&entry->configitems))
return LLIST_TO_STRUCTP (llist_tail (&entry->configitems), lumiera_configitem, lookup);
return NULL;
}
/*
Lookup entries
*/
LumieraConfigLookupentry
lumiera_config_lookupentry_init (LumieraConfigLookupentry self, const char* key)
{
TRACE (config_lookup, "key = %s", key);
if (self)
{
psplaynode_init (&self->node);
llist_init (&self->configitems);
self->full_key = lumiera_strndup (key, SIZE_MAX);
}
return self;
}
LumieraConfigLookupentry
lumiera_config_lookupentry_new (const char* key)
{
return lumiera_config_lookupentry_init (lumiera_malloc (sizeof (lumiera_config_lookupentry)), key);
}
LumieraConfigLookupentry
lumiera_config_lookupentry_destroy (LumieraConfigLookupentry self)
{
TRACE (config_lookup);
if (self)
{
REQUIRE (llist_is_empty (&self->configitems), "lookup node still in use");
lumiera_free (self->full_key);
}
return self;
}
void
lumiera_config_lookupentry_delete (LumieraConfigLookupentry self)
{
lumiera_free (lumiera_config_lookupentry_destroy (self));
}
static int
cmp_fn (const void* a, const void* b)
{
return strcmp ((const char*)a, (const char*)b);
}
static void
delete_fn (PSplaynode node)
{
lumiera_config_lookupentry_delete ((LumieraConfigLookupentry) node);
}
static const void*
key_fn (const PSplaynode node)
{
return ((LumieraConfigLookupentry) node)->full_key;
}
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

192
src/backend/config_lookup.h Normal file
View file

@ -0,0 +1,192 @@
/*
config_lookup.h - Lookup functions for the config subsystem
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LUMIERA_CONFIG_LOOKUP_H
#define LUMIERA_CONFIG_LOOKUP_H
#include "lib/psplay.h"
#include "lib/llist.h"
#include "lib/error.h"
typedef struct lumiera_config_lookup_struct lumiera_config_lookup;
typedef lumiera_config_lookup* LumieraConfigLookup;
typedef struct lumiera_config_lookupentry_struct lumiera_config_lookupentry;
typedef lumiera_config_lookupentry* LumieraConfigLookupentry;
#include "backend/configitem.h"
#include <nobug.h>
/**
* @file
* Lookup of configuration keys. Configuration keys are dynamically stored in a splay tree.
* This happens for defaults, loaded config files and entries which are set explicitly.
* The system maintains no central registry of all possible keys.
* We store here the full keys of configentries as well as the keys of section prefixes.
* Section prefixes are stored with a trailing dot to disambiguate them from entry keys.
*/
LUMIERA_ERROR_DECLARE (CONFIG_LOOKUP);
/**
* Just contains a hashtable to give sufficent abstraction.
*/
struct lumiera_config_lookup_struct
{
psplay tree;
};
/**
* Initialize a lookup structure.
* @param self lookup structure to be initialized
* @return self on success else NULL
*/
LumieraConfigLookup
lumiera_config_lookup_init (LumieraConfigLookup self);
/**
* Destruct a lookup structure.
* @param self lookup structure to be destructed
* @return self
*/
LumieraConfigLookup
lumiera_config_lookup_destroy (LumieraConfigLookup self);
/**
* Add a config item to a lookup structure.
* Config items are stored under their key and stacked in insertion order.
* @param self lookup structure where the item shall be added
* @param item config item to add to the lookup structure
* @return opaque pointer to a hashtable entry
*/
LumieraConfigLookupentry
lumiera_config_lookup_insert (LumieraConfigLookup self, LumieraConfigitem item);
/**
* Add a default config item to a lookup structure.
* @internal
* This function is used internal.
* The item must contain a full key and not part of any 'section'
* and is inserted as tail of the lookup list.
* @param self lookup structure where the item shall be added
* @param item config item to add to the lookup structure
* @return opaque pointer to a hashtable entry
*/
LumieraConfigLookupentry
lumiera_config_lookup_insert_default (LumieraConfigLookup self, LumieraConfigitem item);
/**
* Remove a config item from a lookup structure.
* Config must be removed from the lookup when they are not used anymore.
* Removing a config item unlinks it from the stack of all config items with the same key.
* When this was the last config item under that key, the lookup entry is cleaned up.
* @param self lookup structure where the item shall be removed
* @param item config item to be removed from the lookup
* @return item
*/
LumieraConfigitem
lumiera_config_lookup_remove (LumieraConfigLookup self, LumieraConfigitem item);
/**
* Find a hashtable entry in the lookup structure.
* Internal function, can be used to check if at least one item is available for a given key.
* @param self lookup structure where the key shall be searched
* @param key string to be looked up
* @return NULL if nothing is found, otherwise a opaque pointer to a hash table entry
*/
LumieraConfigLookupentry
lumiera_config_lookup_find (LumieraConfigLookup self, const char* key);
/**
* Find a the topmost config item stored to a given key.
* @param self lookup structure where the key shall be searched
* @param key string to be looked up
* @return the config item which was last stored under the given key or NULL when nothing was found
*/
LumieraConfigitem
lumiera_config_lookup_item_find (LumieraConfigLookup self, const char* key);
/**
* Find a the bottommost config item stored to a given key.
* defaults sits at the bottom if exists
* @param self lookup structure where the key shall be searched
* @param key string to be looked up
* @return TODO
*/
LumieraConfigitem
lumiera_config_lookup_item_tail_find (LumieraConfigLookup self, const char* key);
/*
Lookup hash entries for the cuckoo hash
*/
/**
* Structure defining single hash table entries.
* @internal
*/
struct lumiera_config_lookupentry_struct
{
psplaynode node;
/* stack of all configitems stored under this key */
llist configitems;
/*
we store a copy of the full key here
configentry keys are complete as expected
section keys are the prefix stored with a trailing dot,
suffixes will be found by iterative search
*/
char* full_key;
};
/* internal */
LumieraConfigLookupentry
lumiera_config_lookupentry_init (LumieraConfigLookupentry self, const char* key);
LumieraConfigLookupentry
lumiera_config_lookupentry_new (const char* key);
/* internal */
LumieraConfigLookupentry
lumiera_config_lookupentry_destroy (LumieraConfigLookupentry self);
void
lumiera_config_lookupentry_delete (LumieraConfigLookupentry self);
#endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

313
src/backend/config_typed.c Normal file
View file

@ -0,0 +1,313 @@
/*
config_typed.c - Lumiera configuration highlevel interface
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
//TODO: Support library includes//
#include "lib/safeclib.h"
//TODO: Lumiera header includes//
#include "backend/config.h"
//TODO: internal/static forward declarations//
extern LumieraConfig lumiera_global_config;
//TODO: System includes//
#include <stdint.h>
/**
* @file
* Here are the high level typed configuration interfaces defined.
*/
int
lumiera_config_link_get (const char* key, char** value)
{
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
}
int
lumiera_config_link_set (const char* key, char** value)
{
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
}
/**
* Number
* signed integer numbers, in different formats (decimal, hex, oct, binary(for masks))
*/
int
lumiera_config_number_get (const char* key, long long* value)
{
TRACE (config_typed);
int ret = -1;
const char* raw_value = NULL;
LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock)
{
if (!lumiera_config_get (key, &raw_value))
{
if (raw_value)
{
/* got it, scan it */
if (sscanf (raw_value, "%Li", value) == 1)
ret = 0; /* all ok */
else
{
LUMIERA_ERROR_SET (config_typed, CONFIG_SYNTAX_VALUE);
}
}
else
LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY);
}
}
return ret;
}
int
lumiera_config_number_set (const char* key, long long* value)
{
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
}
/**
* Real
* floating point number in standard formats (see printf/scanf)
*/
int
lumiera_config_real_get (const char* key, long double* value)
{
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
}
int
lumiera_config_real_set (const char* key, long double* value)
{
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
}
/**
* String
* unquoted string which covers the whole value area and gets chopped or
* quoted string which preserves leading/trailing spaces
* either single or double quotes are allowed, doubling the quote in a string escapes it
*/
/**
* helper function, takes a raw input string and give a tmpbuf with the string parsed back.
*/
static char*
scan_string (const char* in)
{
/* chop leading blanks */
in += strspn(in, " \t");
char quote = *in;
char* end;
char* ret = NULL;
if (quote == '"' || quote == '\'')
{
/* quoted string */
++in;
end = strchr (in, quote);
while (end && end[1] == quote)
end = strchr (end + 2, quote);
if (end)
{
ret = lumiera_tmpbuf_strndup (in, end - in);
/* replace double quote chars with single one */
char* wpos;
char* rpos;
for (wpos = rpos = ret; *rpos; ++rpos, ++wpos)
{
if (*rpos == quote)
++rpos;
*wpos = *rpos;
}
*wpos = '\0';
}
else
/* quotes doesnt match */
LUMIERA_ERROR_SET (config_typed, CONFIG_SYNTAX_VALUE);
}
else
{
/* unquoted string */
ret = lumiera_tmpbuf_strndup (in, SIZE_MAX);
/* chop trailing blanks */
end = ret + strlen (ret) - 1;
while (end > ret && (*end == ' ' || *end == '\t'))
*end-- = '\0';
}
return ret;
}
int
lumiera_config_string_get (const char* key, char** value)
{
TRACE (config_typed);
int ret = -1;
const char* raw_value = NULL;
LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock)
{
if (!lumiera_config_get (key, &raw_value))
{
if (raw_value)
{
*value = scan_string (raw_value);
if (*value)
ret = 0; /* all ok */
/* else error was raised by scan_string */
}
else
LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY);
}
}
return ret;
}
int
lumiera_config_string_set (const char* key, char** value)
{
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
}
/**
* Word
* A single word, no quotes, chopped
*/
/**
* helper function, takes a raw input string and give a tmpbuf with the word parsed back.
*/
static char*
scan_word (const char* in)
{
/* chop leading blanks */
in += strspn(in, " \t");
char* ret = lumiera_tmpbuf_strndup (in, SIZE_MAX);
char* end = ret;
/* chop trailing blanks */
while (*end != ' ' && *end != '\t')
++end;
*end++ = '\0';
return ret;
}
int
lumiera_config_word_get (const char* key, char** value)
{
TRACE (config_typed, "KEY %s", key);
int ret = -1;
const char* raw_value = NULL;
LUMIERA_RDLOCK_SECTION (config_typed, &lumiera_global_config->lock)
{
if (!lumiera_config_get (key, &raw_value))
{
if (raw_value)
{
*value = scan_word (raw_value);
if (*value)
ret = 0; /* all ok */
}
else
LUMIERA_ERROR_SET (config, CONFIG_NO_ENTRY);
}
}
return ret;
}
int
lumiera_config_word_set (const char* key, char** value)
{
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
}
/**
* Bool
* Bool in various formats, (0,1(!1), yes/no, true/false, on/off, set/clear)
*/
int
lumiera_config_bool_get (const char* key, int* value)
{
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
}
int
lumiera_config_bool_set (const char* key, int* value)
{
TRACE (config_typed);
UNIMPLEMENTED();
return 0;
}
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

74
src/backend/configentry.c Normal file
View file

@ -0,0 +1,74 @@
/*
configentry.c - single entries from configfiles
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
//TODO: Support library includes//
#include "lib/safeclib.h"
//TODO: Lumiera header includes//
#include "backend/configentry.h"
//TODO: internal/static forward declarations//
//TODO: System includes//
/**
* @file
*
*/
//code goes here//
LumieraConfigitem
lumiera_configentry_new (LumieraConfigitem tmp)
{
LumieraConfigentry self = lumiera_malloc (sizeof (*self));
lumiera_configitem_move ((LumieraConfigitem)self, tmp);
TODO ("initialize other stuff here (lookup, parent, ...)");
return (LumieraConfigitem)self;
}
LumieraConfigitem
lumiera_configentry_destroy (LumieraConfigitem self)
{
TODO ("cleanup other stuff here (lookup, parent, ...)");
return self;
}
struct lumiera_configitem_vtable lumiera_configentry_funcs =
{
.new = lumiera_configentry_new,
.destroy = lumiera_configentry_destroy
};
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -1,5 +1,5 @@
/*
locking.h - shared declarations for all locking primitives
configentry.h - single entries from configfiles
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
@ -19,36 +19,49 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LUMIERA_LOCKING_H
#define LUMIERA_LOCKING_H
#ifndef LUMIERA_CONFIGENTRY_H
#define LUMIERA_CONFIGENTRY_H
#include <pthread.h>
#include <errno.h>
//TODO: Support library includes//
//TODO: Forward declarations//
typedef struct lumiera_configentry_struct lumiera_configentry;
typedef lumiera_configentry* LumieraConfigentry;
//TODO: Lumiera header includes//
#include "backend/configitem.h"
//TODO: System includes//
#include <nobug.h>
#include "lib/error.h"
LUMIERA_ERROR_DECLARE (MUTEX_LOCK);
LUMIERA_ERROR_DECLARE (MUTEX_UNLOCK);
LUMIERA_ERROR_DECLARE (MUTEX_DESTROY);
/**
* @file
* Shared declarations for all locking primitives.
*/
/**
* used to store the current lock state.
*
*
*/
enum lumiera_lockstate
{
LUMIERA_UNLOCKED,
LUMIERA_LOCKED,
LUMIERA_RDLOCKED,
LUMIERA_WRLOCKED
};
//TODO: declarations go here//
struct lumiera_configentry_struct
{
lumiera_configitem entry;
};
extern struct lumiera_configitem_vtable lumiera_configentry_funcs;
LumieraConfigitem
lumiera_configentry_new (LumieraConfigitem tmp);
LumieraConfigitem
lumiera_configentry_destroy (LumieraConfigitem self);
#endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

392
src/backend/configitem.c Normal file
View file

@ -0,0 +1,392 @@
/*
configitem.c - generalized hierachy of configuration items
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
Simeon Voelkel <simeon_voelkel@arcor.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
//TODO: Support library includes//
#include "lib/llist.h"
#include "lib/safeclib.h"
//TODO: Lumiera header includes//
#include "backend/config.h"
#include "backend/configitem.h"
#include "backend/configentry.h"
//TODO: internal/static forward declarations//
//TODO: System includes//
#include <ctype.h>
#include <stdint.h>
/**
* @file
*
*/
//code goes here//
LumieraConfigitem
lumiera_configitem_init (LumieraConfigitem self)
{
TRACE (config_item);
REQUIRE (self);
llist_init (&self->link);
self->parent = NULL;
llist_init (&self->childs);
llist_init (&self->lookup);
self->line = NULL;
self->key = NULL;
self->key_size = 0;
self->delim = NULL;
self->vtable = NULL;
return self;
}
LumieraConfigitem
lumiera_configitem_destroy (LumieraConfigitem self, LumieraConfigLookup lookup)
{
TRACE (config_item);
if (self)
{
LLIST_WHILE_HEAD (&self->childs, node)
lumiera_configitem_delete ((LumieraConfigitem) node, lookup);
ENSURE (llist_is_empty (&self->childs), "destructor didn't remove childs");
if (self->vtable && self->vtable->destroy)
self->vtable->destroy (self);
if (!llist_is_empty (&self->lookup))
lumiera_config_lookup_remove (lookup, self);
llist_unlink (&self->link);
lumiera_free (self->line);
}
return self;
}
LumieraConfigitem
lumiera_configitem_new (const char* line)
{
TRACE (config_item);
lumiera_configitem tmp;
lumiera_configitem_init (&tmp);
lumiera_configitem_parse (&tmp, line);
LumieraConfigitem self = tmp.vtable && tmp.vtable->new
? tmp.vtable->new (&tmp)
: lumiera_configitem_move (lumiera_malloc (sizeof (*self)), &tmp);
return self;
}
void
lumiera_configitem_delete (LumieraConfigitem self, LumieraConfigLookup lookup)
{
TRACE (config_item);
lumiera_free (lumiera_configitem_destroy (self, lookup));
}
LumieraConfigitem
lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem source)
{
TRACE (config_item);
REQUIRE (self);
REQUIRE (source);
llist_init (&self->link);
llist_insertlist_next (&self->link, &source->link);
self->parent = source->parent;
llist_init (&self->childs);
llist_insertlist_next (&self->childs, &source->childs);
llist_init (&self->lookup);
llist_insertlist_next (&self->lookup, &source->lookup);
self->line = source->line;
source->line = NULL;
self->key = source->key;
self->key_size = source->key_size;
self->delim = source->delim;
self->vtable = source->vtable;
return self;
}
LumieraConfigitem
lumiera_configitem_parse (LumieraConfigitem self, const char* line)
{
TRACE (config_item);
self->line = lumiera_strndup (line, SIZE_MAX);
FIXME ("MOCKUP START");
TODO ("parsing here");
/*
HOWTO parse (for simav)
in self->line liegt jetzt der 'rohe' string
parsen setzt folgende werte in self: .key, .key_size, .delim und vtable. den rest macht dann die 'new' funktion aus der vtable
es geht jetzt da drum rauszufinden ob diese zeile einses der folgenden sachen ist:
(ich zeig hier nur die grundsyntax, das parsen sollte auch entartete situationen behandeln, insbesondere leerzeichen/tabulatoren an allen moeglichen stellen)
auserdem sollt hier alles soweit wie moeglich validiert werden z.b. keys auf erlaubte zeichen gescheckt (siehe die _tr function)
section:
'[prefix suffix]'
.key == prefix
.delim == das leerzeichen (oder tab) vor suffix oder aufs abschliessende ] wenn kein suffix
kommentar:
leere zeile, zeile nur aus leerzeichen und tabulatoren, leerzeichen und tabulatoren gefolgt von # bis zum zeilenende
alles ausser vtable auf NULL
direktive:
'@direktive argumente'
.key == @
.delim == leerzeichen oder tab vor argumente, NULL wenn keine argumente
configentry:
'key = value'
.key == key begin
.delim == '='
'key < redirect'
.key == key begin
.delim == '>'
*/
/*
* What should be working (for cehteh) or not yet..
*
* die Elemente sollten bereits richtig unterschieden werden, die {} sind noch zu füllen.
*
* */
char* itr = self->line;
/*skip leading whitespaces*/
while (*itr && isspace (*itr))
itr++;
/*decide what this line represents*/
if (!*itr || *itr == '#' )
{
/*this is an empty line or a a comment*/
}
else if (*itr == '@' )
{
/*this is a directive*/
/*itr points now to @*/
self->key = itr;
/*check whether there are illegal whitespaces after @*/
itr++;
if (*itr && !isspace(*itr))
{
/*now look for the end of the directive and set the keysize*/
self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS);
itr += self->key_size;
/*we need a key with a length greather than zero and
* either the end of the line
* or a whitespace after the key */
if ( self->key_size && ( !*itr || (*itr && isspace(*itr)) ))
{
/*look for given arguments*/
/*skip blanks*/
while (*itr && isspace (*itr))
itr++;
if (*itr)
{
/*there are arguments given, thus set delim*/
self->delim = itr - 1;
}
else
{
/*no arguments were given*/
self->delim = NULL;
}
}
else
{
/*malformed lines shall be treated like if they were comments*/
self->key = NULL;
self->key_size = 0;
LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX);
}
}
else
{
/*there occurred already an error right after the @!*/
/*malformed lines shall be treated like if they were comments*/
self->key = NULL;
self->key_size = 0;
LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX);
}
}
else if (*itr == '[' )
{
/*this is a section*/
/*skip blanks before prefix*/
itr++;
while (*itr && isspace(*itr))
itr++;
/*itr points now to the begin of the key*/
self->key = itr;
/*now look for the end of the key and set the keysize*/
self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS);
itr += self->key_size;
/*if the line ends ends with prefix] delim points to ]
* and not the last (blank) character before the final square bracket*/
if (self->key_size && *itr && *itr == ']')
{
self->delim = itr;
TODO("self->vtable = &lumiera_configsection_funcs;");
}
else if (self->key_size && *itr && isspace(*itr))
{
/* skip blanks until we reach the suffix or the final square bracket*/
while (*itr && isspace(*itr))
itr++;
if (*itr && *itr == ']')
{
/*final square bracket reached, so place delim one char before the
* actual position which must be a whitespace: no extra check necessary*/
self->delim = itr - 1;
TODO("self->vtable = &lumiera_configsection_funcs;");
}
else if (*itr)
{
TODO("check wheter suffix is made of legal characters");
/*delim points to the last whitespace before the actual position;
* no extra check needed*/
self->delim = itr - 1;
TODO("self->vtable = &lumiera_configsection_funcs;");
}
else
{
/*malformed section line, treat this line like a comment*/
self->key = NULL;
self->key_size = 0;
LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX);
}
}
else
{
/*error: either *itr is false, points neither to a blank nor to a closed square
* bracket or the key_size is zero*/
/*treat this line like a comment*/
self->key = NULL;
self->key_size = 0;
LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX);
}
}
else
{
/*this is probably a configentry*/
/*itr points now to the first not-whitespace-character*/
self->key = itr;
/*now look for the end of the key and set the keysize*/
self->key_size = strspn (itr, LUMIERA_CONFIG_KEY_CHARS);
/* skip blanks */
itr += self->key_size;
while (*itr && isspace (*itr))
itr++;
if (self->key_size && *itr == '=')
{
/*this configentry assigns a value to a key*/
self->delim = itr;
self->vtable = &lumiera_configentry_funcs;
}
else if (self->key_size && *itr == '<')
{
/*this configentry is a redirect*/
self->delim = itr;
self->vtable = &lumiera_configentry_funcs;
}
else
{
/*this is not a valid configentry; treat this line like a comment*/
self->key = NULL;
self->key_size = 0;
LUMIERA_ERROR_SET (config_item, CONFIG_SYNTAX);
}
}
return self;
}
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

137
src/backend/configitem.h Normal file
View file

@ -0,0 +1,137 @@
/*
configitem.h - generalized hierachy of configuration items
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LUMIERA_CONFIGITEM_H
#define LUMIERA_CONFIGITEM_H
//TODO: Support library includes//
#include "lib/llist.h"
//TODO: Forward declarations//
typedef struct lumiera_configitem_struct lumiera_configitem;
typedef lumiera_configitem* LumieraConfigitem;
struct lumiera_configitem_vtable;
//TODO: Lumiera header includes//
#include "backend/config_lookup.h"
//TODO: System includes//
#include <nobug.h>
/**
* @file
* configitems build a 3 level hierachy:
*
* 1. file:
* contain sections
*
* 2. section:
* [prefix suffix]
* contain lines
*
* 3. lines are
* comment:
* empty line or line only containing spaces and tabs
* line starting with spaces and tabs followed by a #
* directive:
* '@include name' or '@readonly'
* directives are only valid at the toplevel section []
* configurationentry:
* 'key = value' or 'key < redirect'
*/
//TODO: declarations go here//
/**
* @file
* configitems build a 3 level hierachy:
*
* 1. file:
* contain sections
*
* 2. section:
* [prefix suffix]
* contain lines
*
* 3. lines are
* comment:
* empty line or line only containing spaces and tabs
* line starting with spaces and tabs followed by a #
* directive:
* '@include name' or '@readonly'
* directives are only valid at the toplevel section []
* configurationentry:
* 'key = value' or 'key < redirect'
* errorneous:
* any line which cant be parsed
*/
struct lumiera_configitem_vtable
{
LumieraConfigitem (*new)(LumieraConfigitem);
LumieraConfigitem (*destroy)(LumieraConfigitem);
};
struct lumiera_configitem_struct
{
llist link; // all lines on the same hierachy level are linked here (see childs)
LumieraConfigitem parent; // parent section
llist childs; // root node for all lines below this hierachy
llist lookup; // all lines with the same key are stacked up on the loockup
char* line; // raw line as read in allocated here trailing \n will be replaced with \0
char* key; // pointer into line to start of key
size_t key_size;
char* delim; // delimiter, value starts at delim+1
struct lumiera_configitem_vtable* vtable; // functiontable for subclassing
};
LumieraConfigitem
lumiera_configitem_init (LumieraConfigitem self);
LumieraConfigitem
lumiera_configitem_destroy (LumieraConfigitem self, LumieraConfigLookup lookup);
LumieraConfigitem
lumiera_configitem_new (const char* line);
void
lumiera_configitem_delete (LumieraConfigitem self, LumieraConfigLookup lookup);
LumieraConfigitem
lumiera_configitem_parse (LumieraConfigitem self, const char* line);
LumieraConfigitem
lumiera_configitem_move (LumieraConfigitem self, LumieraConfigitem dest);
#endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -50,7 +50,7 @@ lumiera_file_destroy (LumieraFile self)
{
TRACE (file);
lumiera_filedescriptor_release (self->descriptor);
free ((void*)self->name);
lumiera_free (self->name);
return self;
}
@ -67,7 +67,7 @@ void
lumiera_file_delete (LumieraFile self)
{
TRACE (file);
free (lumiera_file_destroy (self));
lumiera_free (lumiera_file_destroy (self));
}
@ -79,7 +79,7 @@ lumiera_file_handle_acquire (LumieraFile self)
REQUIRE (self->descriptor);
REQUIRE (lumiera_fhcache);
LUMIERA_MUTEX_SECTION (file, self->descriptor->rh, &self->descriptor->lock)
LUMIERA_MUTEX_SECTION (file, &self->descriptor->lock)
{
if (!self->descriptor->handle)
/* no handle yet, get a new one */
@ -123,7 +123,7 @@ lumiera_file_handle_release (LumieraFile self)
{
TRACE (file);
LUMIERA_MUTEX_SECTION (file, self->descriptor->rh, &self->descriptor->lock)
LUMIERA_MUTEX_SECTION (file, &self->descriptor->lock)
{
lumiera_filehandlecache_checkin (lumiera_fhcache, self->descriptor->handle);
}

View file

@ -60,7 +60,7 @@ typedef lumiera_file* LumieraFile;
struct lumiera_file_struct
{
const char* name;
char* name;
LumieraFiledescriptor descriptor;
};

View file

@ -21,7 +21,6 @@
#include "lib/mutex.h"
#include "lib/safeclib.h"
#include "lib/cuckoo.h"
#include "backend/file.h"
#include "backend/filedescriptor.h"
@ -32,6 +31,7 @@
#include <fcntl.h>
#include <limits.h>
#include <unistd.h>
#include <errno.h>
NOBUG_DEFINE_FLAG_PARENT (filedescriptor, file_all);
@ -41,46 +41,50 @@ NOBUG_DEFINE_FLAG_PARENT (filedescriptor, file_all);
This registry stores all acquired filedescriptors for lookup, they will be freed when not referenced anymore.
*/
static Cuckoo registry = NULL;
static PSplay registry = NULL;
static lumiera_mutex registry_mutex = {PTHREAD_MUTEX_INITIALIZER};
/*
* setup hashing and compare functions for cuckoo hashing
*/
static size_t
h1 (const void* item, const uint32_t r)
{
const LumieraFiledescriptor i = *(const LumieraFiledescriptor*)item;
return i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK)
^((i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK))>>7)^r;
}
static size_t
h2 (const void* item, const uint32_t r)
{
const LumieraFiledescriptor i = *(const LumieraFiledescriptor*)item;
return i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK)
^((i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK))>>5)^r;
}
static size_t
h3 (const void* item, const uint32_t r)
{
const LumieraFiledescriptor i = *(const LumieraFiledescriptor*)item;
return i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK)
^((i->stat.st_dev^i->stat.st_ino^(i->flags&LUMIERA_FILE_MASK))>>3)^r;
}
static int
cmp (const void* keya, const void* keyb)
cmp_fn (const void* keya, const void* keyb)
{
const LumieraFiledescriptor a = *(const LumieraFiledescriptor*)keya;
const LumieraFiledescriptor b = *(const LumieraFiledescriptor*)keyb;
return a->stat.st_dev == b->stat.st_dev && a->stat.st_ino == b->stat.st_ino
&& (a->flags&LUMIERA_FILE_MASK) == (b->flags&LUMIERA_FILE_MASK);
const LumieraFiledescriptor a = (const LumieraFiledescriptor)keya;
const LumieraFiledescriptor b = (const LumieraFiledescriptor)keyb;
if (a->stat.st_dev < b->stat.st_dev)
return -1;
else if (a->stat.st_dev > b->stat.st_dev)
return 1;
if (a->stat.st_ino < b->stat.st_ino)
return -1;
else if (a->stat.st_ino > b->stat.st_ino)
return 1;
if ((a->flags&LUMIERA_FILE_MASK) < (b->flags&LUMIERA_FILE_MASK))
return -1;
else if ((a->flags&LUMIERA_FILE_MASK) > (b->flags&LUMIERA_FILE_MASK))
return 1;
return 0;
}
static void
delete_fn (PSplaynode node)
{
lumiera_filedescriptor_delete ((LumieraFiledescriptor) node);
}
static const void*
key_fn (const PSplaynode node)
{
return node;
}
void
lumiera_filedescriptor_registry_init (void)
{
@ -88,20 +92,24 @@ lumiera_filedescriptor_registry_init (void)
TRACE (filedescriptor);
REQUIRE (!registry);
registry = cuckoo_new (h1, h2, h3, cmp,
sizeof (LumieraFiledescriptor),
3);
registry = psplay_new (cmp_fn, key_fn, delete_fn);
if (!registry)
LUMIERA_DIE (NO_MEMORY);
RESOURCE_HANDLE_INIT (registry_mutex.rh);
RESOURCE_ANNOUNCE (filedescriptor, "mutex", "filedescriptor registry", &registry, registry_mutex.rh);
}
void
lumiera_filedescriptor_registry_destroy (void)
{
TRACE (filedescriptor);
REQUIRE (!cuckoo_nelements (registry));
REQUIRE (!psplay_nelements (registry));
RESOURCE_FORGET (filedescriptor, registry_mutex.rh);
if (registry)
cuckoo_free (registry);
psplay_destroy (registry);
registry = NULL;
}
@ -112,82 +120,77 @@ lumiera_filedescriptor_acquire (const char* name, int flags)
TRACE (filedescriptor, "%s", name);
REQUIRE (registry, "not initialized");
lumiera_mutexacquirer registry_lock;
lumiera_mutexacquirer_init_mutex (&registry_lock, &registry_mutex, LUMIERA_LOCKED);
LumieraFiledescriptor dest = NULL;
lumiera_filedescriptor fdesc;
fdesc.flags = flags;
if (stat (name, &fdesc.stat) != 0)
LUMIERA_MUTEX_SECTION (filedescriptor, &registry_mutex)
{
if (errno == ENOENT && flags&O_CREAT)
lumiera_filedescriptor fdesc;
fdesc.flags = flags;
if (stat (name, &fdesc.stat) != 0)
{
char* dir = lumiera_tmpbuf_strndup (name, PATH_MAX);
char* slash = dir;
while ((slash = strchr (slash+1, '/')))
if (errno == ENOENT && flags&O_CREAT)
{
*slash = '\0';
INFO (filedescriptor, "try creating dir: %s", dir);
if (mkdir (dir, 0777) == -1 && errno != EEXIST)
char* dir = lumiera_tmpbuf_strndup (name, PATH_MAX);
char* slash = dir;
while ((slash = strchr (slash+1, '/')))
{
*slash = '\0';
INFO (filedescriptor, "try creating dir: %s", dir);
if (mkdir (dir, 0777) == -1 && errno != EEXIST)
{
LUMIERA_ERROR_SET (filedescriptor, ERRNO);
goto error;
}
*slash = '/';
}
int fd;
INFO (filedescriptor, "try creating file: %s", name);
fd = creat (name, 0777);
if (fd == -1)
{
LUMIERA_ERROR_SET (filedescriptor, ERRNO);
goto efile;
goto error;
}
close (fd);
if (stat (name, &fdesc.stat) != 0)
{
/* finally, no luck */
LUMIERA_ERROR_SET (filedescriptor, ERRNO);
goto error;
}
*slash = '/';
}
int fd;
INFO (filedescriptor, "try creating file: %s", name);
fd = creat (name, 0777);
if (fd == -1)
{
LUMIERA_ERROR_SET (filedescriptor, ERRNO);
goto efile;
}
close (fd);
if (stat (name, &fdesc.stat) != 0)
{
/* finally, no luck */
LUMIERA_ERROR_SET (filedescriptor, ERRNO);
goto efile;
}
}
}
/* lookup/create descriptor */
LumieraFiledescriptor dest = &fdesc;
LumieraFiledescriptor* found = cuckoo_find (registry, &dest);
/* lookup/create descriptor */
dest = (LumieraFiledescriptor) psplay_find (registry, &fdesc, 100);
if (!found)
{
TRACE (filedescriptor, "Descriptor not found");
dest = lumiera_filedescriptor_new (&fdesc);
if (!dest)
goto ecreate;
{
TRACE (filedescriptor, "Descriptor not found");
cuckoo_insert (registry, &dest);
}
else
{
TRACE (filedescriptor, "Descriptor already existing");
dest = *found;
++dest->refcount;
dest = lumiera_filedescriptor_new (&fdesc);
if (!dest)
goto error;
psplay_insert (registry, &dest->node, 100);
}
else
{
TRACE (filedescriptor, "Descriptor already existing");
++dest->refcount;
}
error: ;
}
lumiera_mutexacquirer_unlock (&registry_lock);
return dest;
efile:
ecreate:
lumiera_mutexacquirer_unlock (&registry_lock);
return NULL;
}
void
lumiera_filedescriptor_release (LumieraFiledescriptor self)
{
TRACE (filedescriptor);
TRACE (filedescriptor, "%p", self);
if (!--self->refcount)
lumiera_filedescriptor_delete (self);
}
@ -199,17 +202,14 @@ lumiera_filedescriptor_new (LumieraFiledescriptor template)
LumieraFiledescriptor self = lumiera_malloc (sizeof (lumiera_filedescriptor));
TRACE (filedescriptor, "at %p", self);
psplaynode_init (&self->node);
self->stat = template->stat;
self->flags = template->flags;
lumiera_mutex_init (&self->lock);
self->refcount = 1;
self->handle = 0;
const char* type = "mutex";
const char* name = "filedescriptor";
RESOURCE_ANNOUNCE (filedescriptor, type, name, self, self->rh);
lumiera_mutex_init (&self->lock, "filedescriptor", &NOBUG_FLAG (filedescriptor));
return self;
}
@ -219,22 +219,19 @@ void
lumiera_filedescriptor_delete (LumieraFiledescriptor self)
{
TRACE (filedescriptor, "%p", self);
lumiera_mutexacquirer registry_lock;
lumiera_mutexacquirer_init_mutex (&registry_lock, &registry_mutex, LUMIERA_LOCKED);
REQUIRE (self->refcount == 0);
LUMIERA_MUTEX_SECTION (filedescriptor, &registry_mutex)
{
REQUIRE (self->refcount == 0);
RESOURCE_FORGET (filedescriptor, self->rh);
psplay_remove (registry, &self->node);
cuckoo_remove (registry, cuckoo_find (registry, &self));
TODO ("destruct other members (WIP)");
TODO ("destruct other members (WIP)");
TODO ("release filehandle");
TODO ("release filehandle");
lumiera_mutex_destroy (&self->lock);
free (self);
lumiera_mutexacquirer_unlock (&registry_lock);
lumiera_mutex_destroy (&self->lock, &NOBUG_FLAG (filedescriptor));
lumiera_free (self);
}
}

View file

@ -23,6 +23,7 @@
#define LUMIERA_FILEDESCRIPTOR_H
#include "lib/mutex.h"
#include "lib/psplay.h"
#include <sys/types.h>
@ -47,7 +48,8 @@ typedef lumiera_filedescriptor* LumieraFiledescriptor;
struct lumiera_filedescriptor_struct
{
struct stat stat; /* create after first open, maintained metadata, MUST BE FIRST! */
psplaynode node; /* node for the lookup tree */
struct stat stat; /* create after first open, maintained metadata */
int flags; /* open flags, must be masked for reopen */
lumiera_mutex lock; /* locks operations on this file descriptor */
unsigned refcount; /* reference counter, all users sans registry */
@ -55,8 +57,6 @@ struct lumiera_filedescriptor_struct
LumieraFilehandle handle;
//LumieraFileMap mappings;
//LumieraWriteBuffer writebuffer;
RESOURCE_HANDLE (rh);
};
/**

View file

@ -44,8 +44,7 @@ lumiera_filehandlecache_new (int max_entries)
lumiera_mrucache_init (&lumiera_fhcache->cache, lumiera_filehandle_destroy_node);
lumiera_fhcache->available = max_entries;
lumiera_fhcache->checked_out = 0;
lumiera_mutex_init (&lumiera_fhcache->lock);
RESOURCE_ANNOUNCE (filehandlecache, "mutex", "filehandlecache", lumiera_fhcache, lumiera_fhcache->rh);
lumiera_mutex_init (&lumiera_fhcache->lock, "filehandlecache", &NOBUG_FLAG (filehandlecache));
}
@ -55,10 +54,9 @@ lumiera_filehandlecache_delete (void)
if (lumiera_fhcache)
{
REQUIRE (!lumiera_fhcache->checked_out, "Filehandles in use at shutdown");
RESOURCE_FORGET (filehandlecache, lumiera_fhcache->rh);
lumiera_mrucache_destroy (&lumiera_fhcache->cache);
lumiera_mutex_destroy (&lumiera_fhcache->lock);
free (lumiera_fhcache);
lumiera_mutex_destroy (&lumiera_fhcache->lock, &NOBUG_FLAG (filehandlecache));
lumiera_free (lumiera_fhcache);
lumiera_fhcache = NULL;
}
}
@ -69,7 +67,8 @@ lumiera_filehandlecache_handle_acquire (LumieraFilehandlecache self, LumieraFile
{
TRACE (filehandlecache);
LumieraFilehandle ret = NULL;
LUMIERA_MUTEX_SECTION (filehandlecache, self->rh, &self->lock)
LUMIERA_MUTEX_SECTION (filehandlecache, &self->lock)
{
if (self->available <= 0 && self->cache.cached)
{
@ -106,7 +105,7 @@ lumiera_filehandlecache_checkout (LumieraFilehandlecache self, LumieraFilehandle
if (!handle->use_cnt)
{
/* lock cache and checkout */
LUMIERA_MUTEX_SECTION (filehandlecache, self->rh, &self->lock)
LUMIERA_MUTEX_SECTION (filehandlecache, &self->lock)
{
lumiera_mrucache_checkout (&self->cache, &handle->cachenode);
}
@ -128,7 +127,7 @@ lumiera_filehandlecache_checkin (LumieraFilehandlecache self, LumieraFilehandle
if (!--handle->use_cnt)
{
/* lock cache and checin */
LUMIERA_MUTEX_SECTION (filehandlecache, self->rh, &self->lock)
LUMIERA_MUTEX_SECTION (filehandlecache, &self->lock)
{
--self->checked_out;
lumiera_mrucache_checkin (&self->cache, &handle->cachenode);

View file

@ -49,7 +49,6 @@ struct lumiera_filehandlecache_struct
int available;
int checked_out;
lumiera_mutex lock;
RESOURCE_HANDLE (rh);
};
extern LumieraFilehandlecache lumiera_fhcache;

View file

@ -52,7 +52,7 @@ namespace util
/** create as a tokenized <i>copy</i> of the current commandline.
* Note that argv[0] is allways ignored. */
Cmdline::Cmdline (int argc, char* argv[])
Cmdline::Cmdline (int argc, const char** argv)
: vector<string> (noneg(argc-1))
{
for (int i=1; i<argc; ++i)

View file

@ -48,7 +48,7 @@ namespace util
class Cmdline : public VectS
{
public:
Cmdline (int argc, char* argv[]);
Cmdline (int argc, const char** argv);
explicit Cmdline (const string cmdline);
operator string () const;

View file

@ -128,10 +128,12 @@ namespace lumiera
{
const Error* err=dynamic_cast<const Error*> (&cause);
if (err)
if (isnil (err->cause_))
return cause.what(); // cause is root cause
else
return err->cause_; // cause was caused by another exception
{
if (isnil (err->cause_))
return cause.what(); // cause is root cause
else
return err->cause_; // cause was caused by another exception
}
// unknown other exception type
return cause.what ();

View file

@ -26,27 +26,26 @@ liblumi_a_SOURCES = \
$(liblumi_a_srcdir)/mutex.c \
$(liblumi_a_srcdir)/rwlock.c \
$(liblumi_a_srcdir)/condition.c \
$(liblumi_a_srcdir)/references.c \
$(liblumi_a_srcdir)/uuid.c \
$(liblumi_a_srcdir)/luid.c \
$(liblumi_a_srcdir)/safeclib.c \
$(liblumi_a_srcdir)/cuckoo.c \
$(liblumi_a_srcdir)/psplay.c \
$(liblumi_a_srcdir)/mrucache.c \
$(liblumi_a_srcdir)/time.c \
$(liblumi_a_srcdir)/time.c \
$(liblumi_a_srcdir)/appconfig.cpp
noinst_HEADERS += \
$(liblumi_a_srcdir)/plugin.h \
$(liblumi_a_srcdir)/error.h \
$(liblumi_a_srcdir)/locking.h \
$(liblumi_a_srcdir)/mutex.h \
$(liblumi_a_srcdir)/rwlock.h \
$(liblumi_a_srcdir)/condition.h \
$(liblumi_a_srcdir)/references.h \
$(liblumi_a_srcdir)/uuid.h \
$(liblumi_a_srcdir)/luid.h \
$(liblumi_a_srcdir)/safeclib.h \
$(liblumi_a_srcdir)/cuckoo.h \
$(liblumi_a_srcdir)/psplay.h \
$(liblumi_a_srcdir)/mrucache.h \
$(liblumi_a_srcdir)/time.h \
$(liblumi_a_srcdir)/time.h \
$(liblumi_a_srcdir)/appconfig.hpp \
$(liblumi_a_srcdir)/lifecycleregistry.hpp

View file

@ -28,36 +28,32 @@
LUMIERA_ERROR_DEFINE (CONDITION_DESTROY, "condition destroy failed");
/**
* Initialize a condition variable
* @param self is a pointer to the condition variable to be initialized
* @return self as given
*/
LumieraCondition
lumiera_condition_init (LumieraCondition self)
lumiera_condition_init (LumieraCondition self, const char* purpose, struct nobug_flag* flag)
{
if (self)
{
pthread_cond_init (&self->cond, NULL);
pthread_mutex_init (&self->mutex, NULL);
NOBUG_RESOURCE_HANDLE_INIT (self->rh);
NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "cond_var", purpose, self, self->rh);
}
return self;
}
/**
* Destroy a condition variable
* @param self is a pointer to the condition variable to be destroyed
* @return self as given
*/
LumieraCondition
lumiera_condition_destroy (LumieraCondition self)
lumiera_condition_destroy (LumieraCondition self, struct nobug_flag* flag)
{
if (self)
{
NOBUG_RESOURCE_FORGET_RAW (flag, self->rh);
if (pthread_mutex_destroy (&self->mutex))
LUMIERA_DIE (MUTEX_DESTROY);
else if (pthread_cond_destroy (&self->cond))
if (pthread_cond_destroy (&self->cond))
LUMIERA_DIE (CONDITION_DESTROY);
}
return self;

View file

@ -22,7 +22,9 @@
#ifndef LUMIERA_CONDITION_H
#define LUMIERA_CONDITION_H
#include "lib/locking.h"
#include "lib/error.h"
#include "lib/mutex.h"
/**
* @file
@ -31,6 +33,49 @@
LUMIERA_ERROR_DECLARE (CONDITION_DESTROY);
/**
* Condition section.
* Locks the condition mutex, one can use LUMIERA_CONDITION_WAIT to wait for signals or
* LUMIERA_CONDITION_SIGNAL or LUMIERA_CONDITION_BROADCAST to wake waiting threads
*/
#define LUMIERA_CONDITION_SECTION(nobugflag, cnd) \
for (lumiera_conditionacquirer NOBUG_CLEANUP(lumiera_conditionacquirer_ensureunlocked) \
lumiera_condition_section_ = {(LumieraCondition)1}; \
lumiera_condition_section_.condition;) \
for ( \
({ \
lumiera_condition_section_.condition = (cnd); \
NOBUG_IF(NOBUG_MODE_ALPHA, lumiera_condition_section_.flag = &NOBUG_FLAG(nobugflag)); \
NOBUG_RESOURCE_HANDLE_INIT (lumiera_condition_section_.rh); \
RESOURCE_ENTER (nobugflag, (cnd)->rh, "acquire condition", &lumiera_condition_section_, \
NOBUG_RESOURCE_EXCLUSIVE, lumiera_condition_section_.rh); \
if (pthread_mutex_lock (&(cnd)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \
}); \
lumiera_condition_section_.condition; \
({ \
if (lumiera_condition_section_.condition) \
{ \
pthread_mutex_unlock (&lumiera_condition_section_.condition->mutex); \
lumiera_condition_section_.condition = NULL; \
RESOURCE_LEAVE(nobugflag, lumiera_condition_section_.rh); \
} \
}))
#define LUMIERA_CONDITION_WAIT \
do { \
NOBUG_RESOURCE_STATE_RAW (lumiera_condition_section_.flag, lumiera_condition_section_.rh, NOBUG_RESOURCEING); \
pthread_cond_wait (&lumiera_condition_section_.condition->cond, &lumiera_condition_section_.condition->mutex); \
NOBUG_RESOURCE_STATE_RAW (lumiera_condition_section_.flag, lumiera_condition_section_.rh, NOBUG_RESOURCE_EXCLUSIVE); \
while (0)
#define LUMIERA_CONDITION_SIGNAL (nobugflag) pthread_cond_signal (&lumiera_condition_section_.condition->cond)
#define LUMIERA_CONDITION_BROADCAST (nobugflag) pthread_cond_broadcast (&lumiera_condition_section_.condition->cond)
/**
* Condition variables.
*
@ -39,17 +84,28 @@ struct lumiera_condition_struct
{
pthread_cond_t cond;
pthread_mutex_t mutex;
RESOURCE_HANDLE (rh);
};
typedef struct lumiera_condition_struct lumiera_condition;
typedef lumiera_condition* LumieraCondition;
/**
* Initialize a condition variable
* @param self is a pointer to the condition variable to be initialized
* @return self as given
*/
LumieraCondition
lumiera_condition_init (LumieraCondition self);
lumiera_condition_init (LumieraCondition self, const char* purpose, struct nobug_flag* flag);
/**
* Destroy a condition variable
* @param self is a pointer to the condition variable to be destroyed
* @return self as given
*/
LumieraCondition
lumiera_condition_destroy (LumieraCondition self);
lumiera_condition_destroy (LumieraCondition self, struct nobug_flag* flag);
/**
@ -91,8 +147,9 @@ lumiera_condition_broadcast (LumieraCondition self)
*/
struct lumiera_conditionacquirer_struct
{
LumieraCondition cond;
enum lumiera_lockstate state;
LumieraCondition condition;
NOBUG_IF(NOBUG_MODE_ALPHA, struct nobug_flag* flag);
RESOURCE_HANDLE (rh);
};
typedef struct lumiera_conditionacquirer_struct lumiera_conditionacquirer;
typedef struct lumiera_conditionacquirer_struct* LumieraConditionacquirer;
@ -101,108 +158,15 @@ typedef struct lumiera_conditionacquirer_struct* LumieraConditionacquirer;
static inline void
lumiera_conditionacquirer_ensureunlocked (LumieraConditionacquirer self)
{
ENSURE (self->state == LUMIERA_UNLOCKED, "forgot to unlock the condition mutex");
}
/* override with a macro to use the cleanup checker */
#define lumiera_conditionacquirer \
lumiera_conditionacquirer NOBUG_CLEANUP(lumiera_conditionacquirer_ensureunlocked)
/**
* initialize a conditionacquirer state
* @param self conditionacquirer to be initialized, must be an automatic variable
* @param cond associated condition variable
* @param state initial state of the mutex, either LUMIERA_LOCKED or LUMIERA_UNLOCKED
* @return self as given
* errors are fatal
*/
static inline LumieraConditionacquirer
lumiera_conditionacquirer_init (LumieraConditionacquirer self, LumieraCondition cond, enum lumiera_lockstate state)
{
REQUIRE (self);
REQUIRE (cond);
self->cond = cond;
self->state = state;
if (state == LUMIERA_LOCKED)
if (pthread_mutex_lock (&cond->mutex))
LUMIERA_DIE (MUTEX_LOCK);
return self;
}
/**
* lock the mutex.
* must not already be locked
* @param self conditionacquirer associated with a condition variable
*/
static inline void
lumiera_conditionacquirer_lock (LumieraConditionacquirer self)
{
REQUIRE (self);
REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked");
if (pthread_mutex_lock (&self->cond->mutex))
LUMIERA_DIE (MUTEX_LOCK);
self->state = LUMIERA_LOCKED;
}
/**
* wait on a locked condition.
* Waits until the condition variable gets signaled from another thread. Must already be locked.
* @param self conditionacquirer associated with a condition variable
*/
static inline void
lumiera_conditionacquirer_wait (LumieraConditionacquirer self)
{
REQUIRE (self);
REQUIRE (self->state == LUMIERA_LOCKED, "mutex must be locked");
pthread_cond_wait (&self->cond->cond, &self->cond->mutex);
}
/**
* release mutex.
* a conditionacquirer must be unlocked before leaving scope
* @param self conditionacquirer associated with a condition variable
*/
static inline void
lumiera_conditionacquirer_unlock (LumieraConditionacquirer self)
{
REQUIRE (self);
REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked");
if (pthread_mutex_unlock (&self->cond->mutex))
LUMIERA_DIE (MUTEX_UNLOCK);
self->state = LUMIERA_UNLOCKED;
}
/**
* signal a single waiting thread
* @param self conditionacquirer associated with the condition variable to be signaled
*/
static inline void
lumiera_conditionacquirer_signal (LumieraConditionacquirer self)
{
REQUIRE (self);
REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked");
pthread_cond_signal (&self->cond->cond);
}
/**
* signal all waiting threads
* @param self conditionacquirer associated with the condition variable to be signaled
*/
static inline void
lumiera_conditionacquirer_broadcast (LumieraConditionacquirer self)
{
REQUIRE (self);
REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked");
pthread_cond_broadcast (&self->cond->cond);
ENSURE (!self->condition, "forgot to unlock condition variable");
}
#endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -23,6 +23,8 @@
#include <string.h>
#define CUCKOO_GRANULARITY int
enum compact_state
{
COMPACTING_OFF,
@ -35,14 +37,11 @@ struct cuckoo_struct
size_t size; /* t1 = 4*size; t2 = 2*size; t3 = size */
size_t itemsize;
cuckoo_hashfunc h1; /* hash function */
uint32_t r1; /* random, reset for each rehash */
cuckoo_hashfunc h2;
uint32_t r2;
cuckoo_hashfunc h3;
uint32_t r3;
struct cuckoo_vtable vtable;
cuckoo_cmpfunc cmp;
uint32_t r1; /* random, reset for each rehash */
uint32_t r2;
uint32_t r3;
void* t1;
void* t2;
@ -61,28 +60,59 @@ static inline uint32_t cuckoo_fast_prng ()
return rnd = rnd<<1 ^ ((rnd>>30) & 1) ^ ((rnd>>2) & 1);
}
static inline int
iszero (void* mem, size_t size)
{
while (size && !*(CUCKOO_GRANULARITY*)mem)
{
size -= sizeof (CUCKOO_GRANULARITY);
mem += sizeof (CUCKOO_GRANULARITY);
}
return !size;
}
static inline void
xmemmov (void* dst, void* src, size_t size)
{
while (size)
{
size -= sizeof (CUCKOO_GRANULARITY);
*(CUCKOO_GRANULARITY*)(dst + size) = *(CUCKOO_GRANULARITY*)(src + size);
}
}
Cuckoo
cuckoo_init (Cuckoo self,
cuckoo_hashfunc h1,
cuckoo_hashfunc h2,
cuckoo_hashfunc h3,
cuckoo_cmpfunc cmp,
size_t itemsize,
unsigned startsize)
cuckoo_init (Cuckoo self, size_t itemsize, struct cuckoo_vtable* vtable)
{
if (!self)
return NULL;
self->size = 1<<startsize;
self->itemsize = itemsize;
self->h1 = h1;
self->size = 16;
self->itemsize = (itemsize * sizeof (CUCKOO_GRANULARITY)
+ sizeof (CUCKOO_GRANULARITY) - 1) / sizeof (CUCKOO_GRANULARITY); /* round up to next CUCKOO_GRANULARITY boundary */
self->r1 = cuckoo_fast_prng ();
self->h2 = h2;
self->r2 = cuckoo_fast_prng ();
self->h3 = h3;
self->r3 = cuckoo_fast_prng ();
self->cmp = cmp;
if (!vtable->h1 || !vtable->h2 || !vtable->h3)
return NULL;
self->vtable.h1 = vtable->h1;
self->vtable.h2 = vtable->h2;
self->vtable.h3 = vtable->h3;
if (!vtable->cmp)
return NULL;
self->vtable.cmp = vtable->cmp;
self->vtable.dtor = vtable->dtor;
if (vtable->mov)
self->vtable.mov = vtable->mov;
else
self->vtable.mov = xmemmov;
self->t1 = calloc (self->size * 4, itemsize);
self->t2 = calloc (self->size * 2, itemsize);
@ -101,19 +131,15 @@ cuckoo_init (Cuckoo self,
self->autocompact = COMPACTING_AUTO;
self->elements = 0;
return self;
}
Cuckoo
cuckoo_new (cuckoo_hashfunc h1,
cuckoo_hashfunc h2,
cuckoo_hashfunc h3,
cuckoo_cmpfunc cmp,
size_t itemsize,
unsigned startsize)
cuckoo_new (size_t itemsize, struct cuckoo_vtable* vtable)
{
Cuckoo self = malloc (sizeof (struct cuckoo_struct));
if (!cuckoo_init (self, h1, h2, h3, cmp, itemsize, startsize))
if (!cuckoo_init (self, itemsize, vtable))
{
free (self);
return NULL;
@ -126,6 +152,18 @@ cuckoo_destroy (Cuckoo self)
{
if (self)
{
if (self->vtable.dtor)
{
void* elem;
for (elem = self->t1; elem < self->t1 + self->size * 4; elem += self->size)
self->vtable.dtor (elem);
for (elem = self->t2; elem < self->t1 + self->size * 2; elem += self->size)
self->vtable.dtor (elem);
for (elem = self->t3; elem < self->t1 + self->size; elem += self->size)
self->vtable.dtor (elem);
}
free (self->t1);
free (self->t2);
free (self->t3);
@ -135,76 +173,57 @@ cuckoo_destroy (Cuckoo self)
void
cuckoo_free (Cuckoo self)
cuckoo_delete (Cuckoo self)
{
free (cuckoo_destroy (self));
}
static inline int
iszero (void* mem, size_t size)
{
while (size && !*(int*)mem)
{
size -= sizeof (int);
mem += sizeof (int);
}
return !size;
}
static inline void
xmemcpy (void* dst, void* src, size_t size)
{
while (size)
{
size -= sizeof (int);
*(int*)(dst + size) = *(int*)(src + size);
}
}
static int
static void*
cuckoo_insert_internal_ (Cuckoo self, void* item)
{
void* pos;
char tmp[self->itemsize];
CUCKOO_GRANULARITY tmp[self->itemsize / sizeof(CUCKOO_GRANULARITY)];
for (unsigned n = 0; n < self->maxloops; ++n)
{
/* find nest */
pos = self->t1 + self->itemsize * (self->h1 (item, self->r1) % (4*self->size));
pos = self->t1 + self->itemsize * (self->vtable.h1 (item, self->r1) % (4*self->size));
/* kick old egg out */
xmemcpy (tmp, pos, self->itemsize);
if (iszero (pos, self->itemsize))
memset (tmp, 0, self->itemsize);
else
self->vtable.mov (tmp, pos, self->itemsize);
/* lay egg */
xmemcpy (pos, item, self->itemsize);
self->vtable.mov (pos, item, self->itemsize);
if (iszero (tmp, self->itemsize))
return 1;
return pos;
/* find nest */
pos = self->t2 + self->itemsize * (self->h2 (tmp, self->r2) % (2*self->size));
pos = self->t2 + self->itemsize * (self->vtable.h2 (tmp, self->r2) % (2*self->size));
/* kick old egg out */
xmemcpy (item, pos, self->itemsize);
self->vtable.mov (item, pos, self->itemsize);
/* lay egg */
xmemcpy (pos, tmp, self->itemsize);
self->vtable.mov (pos, tmp, self->itemsize);
if (iszero (item, self->itemsize))
return 1;
return pos;
/* find nest */
pos = self->t3 + self->itemsize * (self->h3 (item, self->r3) % self->size);
pos = self->t3 + self->itemsize * (self->vtable.h3 (item, self->r3) % self->size);
/* kick old egg out */
xmemcpy (tmp, pos, self->itemsize);
self->vtable.mov (tmp, pos, self->itemsize);
/* lay egg */
xmemcpy (pos, item, self->itemsize);
self->vtable.mov (pos, item, self->itemsize);
if (iszero (tmp, self->itemsize))
return 1;
return pos;
/* copy tmp to item, which will be reinserted on next interation / after rehashing */
xmemcpy (item, tmp, self->itemsize);
self->vtable.mov (item, tmp, self->itemsize);
}
return 0;
return NULL;
}
@ -230,14 +249,14 @@ cuckoo_rehash (Cuckoo self)
{
for (n = 0; n < self->maxloops; ++n)
{
unsigned hash = self->h1 (pos, self->r1) % (4*self->size);
unsigned hash = self->vtable.h1 (pos, self->r1) % (4*self->size);
if (hash != i)
{
char t[self->itemsize];
void* hpos = self->t1 + self->itemsize * hash;
xmemcpy (t, hpos, self->itemsize);
xmemcpy (hpos, pos, self->itemsize);
xmemcpy (pos, t, self->itemsize);
self->vtable.mov (t, hpos, self->itemsize);
self->vtable.mov (hpos, pos, self->itemsize);
self->vtable.mov (pos, t, self->itemsize);
if (iszero (t, self->itemsize))
break;
}
@ -260,14 +279,14 @@ cuckoo_rehash (Cuckoo self)
{
for (n = 0; n < self->maxloops; ++n)
{
unsigned hash = self->h2 (pos, self->r2) % (2*self->size);
unsigned hash = self->vtable.h2 (pos, self->r2) % (2*self->size);
if (hash != i)
{
char t[self->itemsize];
void* hpos = self->t2 + self->itemsize * hash;
xmemcpy (t, hpos, self->itemsize);
xmemcpy (hpos, pos, self->itemsize);
xmemcpy (pos, t, self->itemsize);
self->vtable.mov (t, hpos, self->itemsize);
self->vtable.mov (hpos, pos, self->itemsize);
self->vtable.mov (pos, t, self->itemsize);
if (iszero (t, self->itemsize))
break;
}
@ -290,14 +309,14 @@ cuckoo_rehash (Cuckoo self)
{
for (n = 0; n < self->maxloops; ++n)
{
unsigned hash = self->h3 (pos, self->r3) % self->size;
unsigned hash = self->vtable.h3 (pos, self->r3) % self->size;
if (hash != i)
{
char t[self->itemsize];
void* hpos = self->t3 + self->itemsize * hash;
xmemcpy (t, hpos, self->itemsize);
xmemcpy (hpos, pos, self->itemsize);
xmemcpy (pos, t, self->itemsize);
self->vtable.mov (t, hpos, self->itemsize);
self->vtable.mov (hpos, pos, self->itemsize);
self->vtable.mov (pos, t, self->itemsize);
if (iszero (t, self->itemsize))
break;
}
@ -314,10 +333,10 @@ static int
cuckoo_grow (Cuckoo self)
{
/* rotate hashfuncs, tables, randoms */
cuckoo_hashfunc th = self->h3;
self->h3 = self->h2;
self->h2 = self->h1;
self->h1 = th;
cuckoo_hashfunc th = self->vtable.h3;
self->vtable.h3 = self->vtable.h2;
self->vtable.h2 = self->vtable.h1;
self->vtable.h1 = th;
uint32_t tr = self->r3;
self->r3 = self->r2;
@ -380,10 +399,10 @@ cuckoo_compact (Cuckoo self)
if (self->size > 2 && self->elements < self->size * 3)
{
cuckoo_hashfunc th = self->h1;
self->h1 = self->h2;
self->h2 = self->h3;
self->h3 = th;
cuckoo_hashfunc th = self->vtable.h1;
self->vtable.h1 = self->vtable.h2;
self->vtable.h2 = self->vtable.h3;
self->vtable.h3 = th;
uint32_t tr = self->r1;
self->r1 = self->r2;
@ -425,7 +444,7 @@ cuckoo_compact (Cuckoo self)
}
int
void*
cuckoo_insert (Cuckoo self, void* item)
{
char tmp[self->itemsize];
@ -433,30 +452,32 @@ cuckoo_insert (Cuckoo self, void* item)
void* found;
if ((found = cuckoo_find (self, item)))
{
xmemcpy (found, item, self->itemsize);
return 1;
if (self->vtable.dtor)
self->vtable.dtor (found);
self->vtable.mov (found, item, self->itemsize);
return found;
}
xmemcpy (tmp, item, self->itemsize);
self->vtable.mov (tmp, item, self->itemsize);
for (unsigned n = 6; n; --n) /* rehash/grow loop */
{
if (cuckoo_insert_internal_ (self, tmp))
if ((found = cuckoo_insert_internal_ (self, tmp)))
{
++self->elements;
return 1;
return found;
}
if (self->elements > n*self->size)
{
n = 6;
if (!cuckoo_grow (self))
return 0;
return NULL;
}
else
cuckoo_rehash (self);
}
return 0;
return NULL;
}
@ -465,16 +486,16 @@ cuckoo_find (Cuckoo self, void* item)
{
void* pos;
pos = self->t1 + self->itemsize * (self->h1 (item, self->r1) % (4*self->size));
if (!iszero (pos, self->itemsize) && self->cmp (item, pos))
pos = self->t1 + self->itemsize * (self->vtable.h1 (item, self->r1) % (4*self->size));
if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos))
return pos;
pos = self->t2 + self->itemsize * (self->h2 (item, self->r2) % (2*self->size));
if (!iszero (pos, self->itemsize) && self->cmp (item, pos))
pos = self->t2 + self->itemsize * (self->vtable.h2 (item, self->r2) % (2*self->size));
if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos))
return pos;
pos = self->t3 + self->itemsize * (self->h3 (item, self->r3) % self->size);
if (!iszero (pos, self->itemsize) && self->cmp (item, pos))
pos = self->t3 + self->itemsize * (self->vtable.h3 (item, self->r3) % self->size);
if (!iszero (pos, self->itemsize) && self->vtable.cmp (item, pos))
return pos;
return NULL;
@ -486,6 +507,9 @@ cuckoo_remove (Cuckoo self, void* item)
{
if (item)
{
if (self->vtable.dtor)
self->vtable.dtor (item);
memset (item, 0, self->itemsize);
--self->elements;

View file

@ -54,41 +54,61 @@ typedef size_t (*cuckoo_hashfunc)(const void* item, const uint32_t r);
*/
typedef int (*cuckoo_cmpfunc)(const void* item1, const void* item2);
/**
* Item destructor function.
* User supplied destructor function. This function is called when items are removed
* from the hash or at hash detroy/delete time. Must be safe to be called on a zeroed element.
* @param item address of the item to be destroyed
*/
typedef void (*cuckoo_dtorfunc)(void* item);
/**
* Move function.
* User supplied item move function
* @param dest target address for the move operation
* @param src source for the move operation
* @param size size of a item (requested size rounded up to the next CUCKOO_GRANULARITY)
* It might be necessary to invalidate the source in some case, cuckoo will zero it out
* after moving.
*/
typedef void (*cuckoo_movfunc)(void* dest, void* src, size_t size);
/**
* Function table used to specialize various funtions used by the hash.
* TODO some elements might be NULL, then defaults are used
*/
struct cuckoo_vtable
{
cuckoo_hashfunc h1;
cuckoo_hashfunc h2;
cuckoo_hashfunc h3;
cuckoo_cmpfunc cmp;
cuckoo_dtorfunc dtor;
cuckoo_movfunc mov;
};
/**
* Initialize a cuckoo hash.
* @param self pointer to a uninitialized cuckoo datastructure
* @param h1 hash function for the first table
* @param h2 hash function for the second table
* @param h3 hash function for the third table
* @param cmp function which compares two keys
* @param startsize initial size of table t3, as 2's exponent
* @param itemsize size for a single hash entry, will be rounded up to align CUCKOO_GRANULARITY
* @param vtable initialized vtable
* @return The initialized hashtable or NULL at allocation failure
*/
Cuckoo
cuckoo_init (Cuckoo self,
cuckoo_hashfunc h1,
cuckoo_hashfunc h2,
cuckoo_hashfunc h3,
cuckoo_cmpfunc cmp,
size_t itemsize,
unsigned startsize);
cuckoo_init (Cuckoo self, size_t itemsize, struct cuckoo_vtable* vtable);
/**
* Allocate a new cuckoo hash.
* @param h1 hash function for the first table
* @param h2 hash function for the second table
* @param h3 hash function for the third table
* @param cmp function which compares two keys
* @param itemsize size for a single hash entry, will be rounded up to align CUCKOO_GRANULARITY
* @param startsize initial size of table t3, as 2's exponent
* @param vtable initialized vtable
* @return The initialized hashtable or NULL at allocation failure
*/
Cuckoo
cuckoo_new (cuckoo_hashfunc h1,
cuckoo_hashfunc h2,
cuckoo_hashfunc h3,
cuckoo_cmpfunc cmp,
size_t itemsize,
unsigned startsize);
cuckoo_new (size_t itemsize, struct cuckoo_vtable* vtable);
/**
* Destroy a cuckoo hash.
@ -104,7 +124,7 @@ cuckoo_destroy (Cuckoo self);
* @param self handle of the hash table to be freed
*/
void
cuckoo_free (Cuckoo self);
cuckoo_delete (Cuckoo self);
/**
* Get the number of elements stored in a hash.
@ -117,12 +137,14 @@ cuckoo_nelements (Cuckoo self);
* Insert an element into a hash.
* amortized O(1) complexity because it may rarely rehash the tables or even grow them.
* see cuckoo_reserve() about how to preallocate entries to prevent the growing costs.
* Inserting an element already in the hash calls the dtor for the old entry and places
* the new one into the hash.
* @param self handle to the hash table
* @param item pointer to a item to be inserted
* @return 1 on successful insert, 0 on allocation failure
* @return pointer to inserted element on successful insert, NULL on allocation failure
* Note: at failure there is one arbitary hash cell lost!
*/
int
void*
cuckoo_insert (Cuckoo self, void* item);
/**

View file

@ -45,19 +45,13 @@ lumiera_error_tls_init (void)
pthread_key_create (&lumiera_error_tls, NULL);
}
/**
* Set error state for the current thread.
* If the error state of the current thread was cleared, then set it, else preserve the old state.
* @param nerr name of the error with 'LUMIERA_ERROR_' prefix (example: LUMIERA_ERROR_NO_MEMORY)
* @return old state, that is NULL for success, when the state was cleared and a pointer to a pending
* error when the error state was already set
*/
const char*
lumiera_error_set (const char * nerr)
lumiera_err
lumiera_error_set (lumiera_err nerr)
{
pthread_once (&lumiera_error_initialized, lumiera_error_tls_init);
const char* err = pthread_getspecific (lumiera_error_tls);
lumiera_err err = pthread_getspecific (lumiera_error_tls);
if (!err)
pthread_setspecific (lumiera_error_tls, nerr);
@ -65,18 +59,12 @@ lumiera_error_set (const char * nerr)
}
/**
* Get and clear current error state.
* This function clears the error state, if it needs to be reused, one has to store it in a temporary
* variable.
* @return pointer to any pending error of this thread, NULL if no error is pending
*/
const char*
lumiera_err
lumiera_error ()
{
pthread_once (&lumiera_error_initialized, lumiera_error_tls_init);
const char* err = pthread_getspecific (lumiera_error_tls);
lumiera_err err = pthread_getspecific (lumiera_error_tls);
if (err)
pthread_setspecific (lumiera_error_tls, NULL);
return err;

View file

@ -35,6 +35,7 @@ extern "C" {
* C Error handling in Lumiera, header.
*/
typedef const char* lumiera_err;
/**
* Abort unconditionally with a 'Fatal Error!' message.
@ -49,7 +50,7 @@ extern "C" {
* @param err name of the error without the 'LUMIERA_ERROR_' prefix (example: NO_MEMORY)
*/
#define LUMIERA_ERROR_DECLARE(err) \
extern const char* LUMIERA_ERROR_##err
extern lumiera_err LUMIERA_ERROR_##err
/**
* Definition and initialization of an error constant.
@ -58,7 +59,7 @@ extern const char* LUMIERA_ERROR_##err
* @param msg message describing the error in plain english (example: "memory allocation failed")
*/
#define LUMIERA_ERROR_DEFINE(err, msg) \
const char* LUMIERA_ERROR_##err = "LUMIERA_ERROR_" #err ":" msg
lumiera_err LUMIERA_ERROR_##err = "LUMIERA_ERROR_" #err ":" msg
/**
* Helper macro to raise an error for the current thread.
@ -70,10 +71,23 @@ const char* LUMIERA_ERROR_##err = "LUMIERA_ERROR_" #err ":" msg
(({ERROR (flag, "%s", strchr(LUMIERA_ERROR_##err, ':')+1);}), \
lumiera_error_set(LUMIERA_ERROR_##err))
const char*
lumiera_error_set (const char * err);
/**
* Set error state for the current thread.
* If the error state of the current thread was cleared, then set it, else preserve the old state.
* @param nerr name of the error with 'LUMIERA_ERROR_' prefix (example: LUMIERA_ERROR_NO_MEMORY)
* @return old state, that is NULL for success, when the state was cleared and a pointer to a pending
* error when the error state was already set
*/
lumiera_err
lumiera_error_set (lumiera_err err);
const char*
/**
* Get and clear current error state.
* This function clears the error state, if it needs to be reused, one has to store it in a temporary
* variable.
* @return pointer to any pending error of this thread, NULL if no error is pending
*/
lumiera_err
lumiera_error ();
/*

View file

@ -299,6 +299,9 @@ LLIST_FUNC (LList llist_unlink (LList self),
/**
* Fix a node which got relocated in memory.
* It is supported to realloc/move list nodes in memory but one must call 'list_relocate' after doing so.
* IMPORTANT: it is not possible to relocate nodes which are empty this way, nor can this be determined
* after the relocation, so either llist_init them afterwards or insert a bogus node before moving the node
* and relocating it and remove it afterwards.
* @param self node which got relocated
* @return self
*/
@ -306,6 +309,7 @@ LLIST_FUNC (LList llist_relocate (LList self),
return self->next->prev = self->prev->next = self;
);
/**
* Insert a node after another.
* @param self node after which we want to insert

113
src/lib/luid.c Normal file
View file

@ -0,0 +1,113 @@
/*
luid - Lumiera unique identifiers
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "lib/luid.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdint.h>
void
lumiera_uid_set_ptr (lumiera_uid* luid, void* ptr)
{
memset (luid, 0, 16);
*(void**)luid = ptr;
}
void*
lumiera_uid_ptr_get (lumiera_uid* luid)
{
return *(void**)luid;
}
void
lumiera_uid_gen (lumiera_uid* luid)
{
static int fd = -2;
if (!luid)
return;
if (fd == -2)
{
fd = open ("/dev/urandom", O_RDONLY);
/* on linux /dev/random would be way to slow for our purpose, so we comment that out for now.
other unixiods offer a /dev/random which has the same semantics as linux /dev/urandom has,
configuration should do this right some day.
if (fd == -1)
fd = open ("/dev/random", O_RDONLY);
*/
if (fd >= 0)
fcntl (fd, F_SETFD, FD_CLOEXEC);
else
srand (getpid () + time (NULL));
}
do
{
if (fd < 0)
{
for (int i = 0; i < 16; ++i)
((unsigned char*)luid)[i] = (unsigned char)(rand()>>7);
}
else
{
if (read (fd, luid, 16) < 16)
abort ();
}
}
/* we identify generic pointers by having some zeros in the luid,
* this happens very unlikely to be in a random luid, just regenerate it then */
while (!*(((intptr_t*)luid)+1));
}
void
lumiera_uid_copy (lumiera_uid* dest, lumiera_uid* src)
{
memcpy (dest, src, 16);
}
int
lumiera_uid_eq (lumiera_uid* luida, lumiera_uid* luidb)
{
return !memcmp (luida, luidb, 16);
}
size_t
lumiera_uid_hash (lumiera_uid* luid)
{
return *(size_t*)luid;
}
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

81
src/lib/luid.h Normal file
View file

@ -0,0 +1,81 @@
/*
luid - Lumiera unique identifiers
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LUMIERA_LUID_H
#define LUMIERA_LUID_H
#include <stdlib.h>
/**
* @file
* Lumiera unique identifiers are 128 byte random value. Unlike standard uuid's we
* don't tag a version within them and we may store generic pointers in the space
* occupied by an luid.
*/
typedef unsigned char lumiera_uid[16];
/**
* Retrieve a generic pointer stored in a luid
*/
void*
lumiera_uid_ptr_get (lumiera_uid* luid);
/**
* Generate a new luid
*/
void
lumiera_uid_gen (lumiera_uid* luid);
/**
* Store a generic pointer in a luid
*/
void
lumiera_uid_set_ptr (lumiera_uid* luid, void* ptr);
/**
* Copy an luid
*/
void
lumiera_uid_copy (lumiera_uid* dest, lumiera_uid* src);
/**
* Test 2 luid's for equality
*/
int
lumiera_uid_eq (lumiera_uid* luida, lumiera_uid* luidb);
/**
* Generate a hashsum over an luid
*/
size_t
lumiera_uid_hash (lumiera_uid* luid);
#endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -19,6 +19,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "lib/safeclib.h"
#include "lib/mrucache.h"
@ -39,9 +40,9 @@ lumiera_mrucache_destroy (LumieraMruCache self)
{
llist_unlink (node);
if (self->destructor_cb)
free (self->destructor_cb (node));
lumiera_free (self->destructor_cb (node));
else
free (node);
lumiera_free (node);
}
self->cached = 0;
return self;
@ -52,7 +53,7 @@ lumiera_mrucache_age (LumieraMruCache self, int nelem)
{
REQUIRE (self);
while (self->cached && nelem--)
free (lumiera_mrucache_pop (self));
lumiera_free (lumiera_mrucache_pop (self));
return nelem;
}

View file

@ -31,34 +31,35 @@ LUMIERA_ERROR_DEFINE (MUTEX_UNLOCK, "Mutex unlocking failed");
LUMIERA_ERROR_DEFINE (MUTEX_DESTROY, "Mutex destroy failed");
/**
* Initialize a mutex variable
* @param self is a pointer to the mutex to be initialized
* @return self as given
*/
LumieraMutex
lumiera_mutex_init (LumieraMutex self)
lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag)
{
if (self)
{
pthread_mutex_init (&self->mutex, NULL);
NOBUG_RESOURCE_HANDLE_INIT (self->rh);
NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "mutex", purpose, self, self->rh);
}
return self;
}
/**
* Destroy a mutex variable
* @param self is a pointer to the mutex to be destroyed
* @return self as given
*/
LumieraMutex
lumiera_mutex_destroy (LumieraMutex self)
lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag)
{
if (self)
{
NOBUG_RESOURCE_FORGET_RAW (flag, self->rh);
if (pthread_mutex_destroy (&self->mutex))
LUMIERA_DIE (MUTEX_DESTROY);
}
return self;
}
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -22,21 +22,43 @@
#ifndef LUMIERA_MUTEX_H
#define LUMIERA_MUTEX_H
#include "lib/locking.h"
#include "lib/error.h"
#include <pthread.h>
#include <nobug.h>
/**
* @file
* Mutual exclusion locking, header.
*/
#define LUMIERA_MUTEX_SECTION(flag, handle, mutex) \
RESOURCE_HANDLE (rh_##__LINE__##_); \
lumiera_mutexacquirer lock_##__LINE__##_; \
RESOURCE_ENTER (flag, handle, "acquire mutex", &lock_##__LINE__##_, \
NOBUG_RESOURCE_EXCLUSIVE, rh_##__LINE__##_); \
for (lumiera_mutexacquirer_init_mutex (&lock_##__LINE__##_, mutex, LUMIERA_LOCKED); \
lock_##__LINE__##_.state == LUMIERA_LOCKED; \
lumiera_mutexacquirer_unlock (&lock_##__LINE__##_), \
({RESOURCE_LEAVE(flag, rh_##__LINE__##_);}))
LUMIERA_ERROR_DECLARE (MUTEX_LOCK);
LUMIERA_ERROR_DECLARE (MUTEX_UNLOCK);
LUMIERA_ERROR_DECLARE (MUTEX_DESTROY);
/**
* Mutual exclusive section.
*/
#define LUMIERA_MUTEX_SECTION(nobugflag, mtx) \
for (lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked) lumiera_mutex_section_ = {(LumieraMutex)1}; \
lumiera_mutex_section_.mutex;) \
for ( \
({ \
lumiera_mutex_section_.mutex = (mtx); \
NOBUG_RESOURCE_HANDLE_INIT (lumiera_mutex_section_.rh); \
RESOURCE_ENTER (nobugflag, (mtx)->rh, "acquire mutex", &lumiera_mutex_section_, \
NOBUG_RESOURCE_EXCLUSIVE, lumiera_mutex_section_.rh); \
if (pthread_mutex_lock (&(mtx)->mutex)) LUMIERA_DIE (MUTEX_LOCK); \
}); \
lumiera_mutex_section_.mutex; \
({ \
if (lumiera_mutex_section_.mutex) \
{ \
pthread_mutex_unlock (&lumiera_mutex_section_.mutex->mutex); \
lumiera_mutex_section_.mutex = NULL; \
RESOURCE_LEAVE(nobugflag, lumiera_mutex_section_.rh); \
} \
}))
/**
@ -46,27 +68,37 @@ for (lumiera_mutexacquirer_init_mutex (&lock_##__LINE__##_, mutex, LUMIERA_LOCKE
struct lumiera_mutex_struct
{
pthread_mutex_t mutex;
RESOURCE_HANDLE (rh);
};
typedef struct lumiera_mutex_struct lumiera_mutex;
typedef lumiera_mutex* LumieraMutex;
/**
* Initialize a mutex variable
* @param self is a pointer to the mutex to be initialized
* @return self as given
*/
LumieraMutex
lumiera_mutex_init (LumieraMutex self);
LumieraMutex
lumiera_mutex_destroy (LumieraMutex self);
lumiera_mutex_init (LumieraMutex self, const char* purpose, struct nobug_flag* flag);
/**
* mutexacquirer used to manage the state of a mutex variable.
* Destroy a mutex variable
* @param self is a pointer to the mutex to be destroyed
* @return self as given
*/
LumieraMutex
lumiera_mutex_destroy (LumieraMutex self, struct nobug_flag* flag);
/**
* mutexacquirer used to manage the state of a mutex.
*/
struct lumiera_mutexacquirer_struct
{
LumieraMutex mutex;
enum lumiera_lockstate state;
RESOURCE_HANDLE (rh);
};
typedef struct lumiera_mutexacquirer_struct lumiera_mutexacquirer;
typedef struct lumiera_mutexacquirer_struct* LumieraMutexacquirer;
@ -75,123 +107,14 @@ typedef struct lumiera_mutexacquirer_struct* LumieraMutexacquirer;
static inline void
lumiera_mutexacquirer_ensureunlocked (LumieraMutexacquirer self)
{
ENSURE (self->state == LUMIERA_UNLOCKED, "forgot to unlock mutex");
}
/* override with a macro to use the cleanup checker */
#define lumiera_mutexacquirer \
lumiera_mutexacquirer NOBUG_CLEANUP(lumiera_mutexacquirer_ensureunlocked)
/**
* initialize a mutexacquirer state without mutex.
* @param self mutexacquirer to be initialized, must be an automatic variable
* @return self as given
* This initialization is used when lumiera_mutexacquirer_try_mutex shall be used later
*/
static inline LumieraMutexacquirer
lumiera_mutexacquirer_init (LumieraMutexacquirer self)
{
REQUIRE (self);
self->mutex = NULL;
self->state = LUMIERA_UNLOCKED;
return self;
}
/**
* initialize a mutexacquirer state
* @param self mutexacquirer to be initialized, must be an automatic variable
* @param mutex associated mutex
* @param state initial state of the mutex, either LUMIERA_LOCKED or LUMIERA_UNLOCKED
* @return self as given
* errors are fatal
*/
static inline LumieraMutexacquirer
lumiera_mutexacquirer_init_mutex (LumieraMutexacquirer self, LumieraMutex mutex, enum lumiera_lockstate state)
{
REQUIRE (self);
REQUIRE (mutex);
self->mutex = mutex;
self->state = state;
if (state == LUMIERA_LOCKED)
if (pthread_mutex_lock (&mutex->mutex))
LUMIERA_DIE (MUTEX_LOCK);
return self;
}
/**
* lock the mutex.
* must not already be locked
* @param self mutexacquirer associated with a mutex variable
*/
static inline void
lumiera_mutexacquirer_lock (LumieraMutexacquirer self)
{
REQUIRE (self);
REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked");
if (pthread_mutex_lock (&self->mutex->mutex))
LUMIERA_DIE (MUTEX_LOCK);
self->state = LUMIERA_LOCKED;
}
/**
* get the state of a lock.
* @param self mutexacquirer associated with a mutex variable
* @return LUMIERA_LOCKED when the mutex is locked by this thead
*/
static inline enum lumiera_lockstate
lumiera_mutexacquirer_state (LumieraMutexacquirer self)
{
REQUIRE (self);
return self->state;
}
/**
* try to lock a mutex.
* must not already be locked
* @param self mutexacquirer associated with a mutex variable
* @param mutex pointer to a mutex which should be tried
* @return LUMIERA_LOCKED when the mutex got locked
*/
static inline enum lumiera_lockstate
lumiera_mutexacquirer_try_mutex (LumieraMutexacquirer self, LumieraMutex mutex)
{
REQUIRE (self);
REQUIRE (self->state == LUMIERA_UNLOCKED, "mutex already locked");
self->mutex=mutex;
switch (pthread_mutex_trylock (&self->mutex->mutex))
{
case 0:
return self->state = LUMIERA_LOCKED;
case EBUSY:
return LUMIERA_UNLOCKED;
default:
LUMIERA_DIE (MUTEX_LOCK);
}
}
/**
* release mutex.
* a mutexacquirer must be unlocked before leaving scope
* @param self mutexacquirer associated with a mutex variable
*/
static inline void
lumiera_mutexacquirer_unlock (LumieraMutexacquirer self)
{
REQUIRE (self);
REQUIRE (self->state == LUMIERA_LOCKED, "mutex was not locked");
if (pthread_mutex_unlock (&self->mutex->mutex))
LUMIERA_DIE (MUTEX_UNLOCK);
self->state = LUMIERA_UNLOCKED;
ENSURE (!self->mutex, "forgot to unlock mutex");
}
#endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -111,10 +111,6 @@ lumiera_plugin_name_cmp (const void* a, const void* b)
return strcmp (((struct lumiera_plugin*) a)->name, ((struct lumiera_plugin*) b)->name);
}
/**
* Initialize the plugin system.
* always succeeds or aborts
*/
void
lumiera_init_plugin (void)
{
@ -173,17 +169,6 @@ lumiera_plugin_lookup (struct lumiera_plugin* self, const char* path)
}
/**
* Make an interface available.
* To use an interface provided by a plugin it must be opened first. It is allowed to open an interface
* more than once. Each open must be paired with a close.
* @param name name of the plugin to use.
* @param interface name of the interface to open.
* @param min_revision the size of the interface structure is used as measure of a minimal required
* revision (new functions are appended at the end)
* @return handle to the interface or NULL in case of a error. The application shall cast this handle to
* the actual interface type.
*/
struct lumiera_interface*
lumiera_interface_open (const char* name, const char* interface, size_t min_revision)
{
@ -311,11 +296,6 @@ lumiera_interface_open (const char* name, const char* interface, size_t min_revi
return NULL;
}
/**
* Close an interface. Does not free associated resources
* Calling this function with self==NULL is legal. Every interface handle must be closed only once.
* @param ptr interface to be closed
*/
void
lumiera_interface_close (void* ptr)
{

View file

@ -96,14 +96,34 @@ struct lumiera_interface
int (*close)(void);
};
/**
* Initialize the plugin system.
* always succeeds or aborts
*/
void
lumiera_init_plugin (void);
/**
* Make an interface available.
* To use an interface provided by a plugin it must be opened first. It is allowed to open an interface
* more than once. Each open must be paired with a close.
* @param name name of the plugin to use.
* @param interface name of the interface to open.
* @param min_revision the size of the interface structure is used as measure of a minimal required
* revision (new functions are appended at the end)
* @return handle to the interface or NULL in case of a error. The application shall cast this handle to
* the actual interface type.
*/
struct lumiera_interface*
lumiera_interface_open (const char* plugin, const char* name, size_t min_revision);
/**
* Close an interface. Does not free associated resources
* Calling this function with self==NULL is legal. Every interface handle must be closed only once.
* @param ptr interface to be closed
*/
void
lumiera_interface_close (void* self);

522
src/lib/psplay.c Normal file
View file

@ -0,0 +1,522 @@
/*
psplay.c - probabilistic splay tree
Copyright (C)
2004, 2005, 2006, Christian Thaeter <chth@gmx.net>
Copyright (C) CinelerraCV
2007, 2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "lib/psplay.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <nobug.h>
NOBUG_DEFINE_FLAG (psplay);
#ifndef PSPLAY_TRAIL_DEPTH
#define PSPLAY_TRAIL_DEPTH 128
#endif
/*
probabilistic distribution, this are the direct splay equations used to determine if to splay
or break out of the splaying algorithm.
useable variables/functions are:
self->log2 - log2 of the tree elements, this would be the depth of a fully balanced tree
splayfactor - user defined weigth for splaying, we define '100' to be the default
depth - depth of the current node in the tree
trail->dir - dervitation from tree center
psplay_fast_prng () - returns a prng in the range 1...2^31
*/
#define PSPLAY_FORMULA (self->log2*100/(depth + (psplay_fast_prng () & 63)) + trail->dir) * splayfactor
#ifndef PSPLAY_PROB_ZIGZIG
#define PSPLAY_PROB_ZIGZIG 5000
#endif
#ifndef PSPLAY_PROB_ZIGZAG
#define PSPLAY_PROB_ZIGZAG 2500
#endif
/* simple prng with 2^31-1 cycle */
static inline uint32_t psplay_fast_prng ()
{
static uint32_t rnd=0xbabeface;
return rnd = rnd<<1 ^ ((rnd >> 30) & 1) ^ ((rnd>>2) & 1);
}
PSplay
psplay_init (PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete)
{
NOBUG_INIT_FLAG (psplay);
TRACE (psplay);
REQUIRE (cmp);
REQUIRE (key);
if (self)
{
self->tree = NULL;
self->found_parent = &self->tree;
self->cmp = cmp;
self->key = key;
self->delete = delete;
self->elem_cnt = 0;
self->log2 = 0;
}
return self;
}
PSplay
psplay_new (psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete)
{
PSplay self = malloc (sizeof *self);
if (self)
{
psplay_init (self , cmp, key, delete);
}
return self;
}
PSplay
psplay_destroy (PSplay self)
{
TRACE (psplay);
if (self) while (self->tree)
{
PSplaynode n = psplay_remove (self, self->tree);
if (self->delete)
self->delete (n);
}
return self;
}
void
psplay_delete (PSplay self)
{
free (psplay_destroy (self));
}
PSplaynode
psplaynode_init (PSplaynode self)
{
if (self)
self->left = self->right = NULL;
return self;
}
/*
Lookup operations (lookup and insert) record the path as they decend into the tree
this will allow bottom up splaying without storing 'up' pointers in the node.
The length of this trail (PSPLAY_TRAIL_DEPTH) also define the maximal limit on how much
a node can be splayed up giving some hard bound for the splay operation.
General wisdom tells that top down splaying is more efficent to implement than bottom
up splaying. Nevertheless we do bottom up splaying here because we can decide
randomly on each level if we want to continue splaying or not. No splaying
is certainly more efficent than top-down splaying.
*/
struct psplaytrail
{
int dir;
unsigned depth;
PSplaynode* trail[PSPLAY_TRAIL_DEPTH];
};
static inline unsigned
trailidx (unsigned n)
{
return n & (PSPLAY_TRAIL_DEPTH-1);
}
static inline void
psplay_splay (PSplay self, struct psplaytrail* trail, unsigned splayfactor)
{
TRACE (psplay, "%p %u", self, splayfactor);
if (trail->dir < 0) trail->dir = - trail->dir;
for (unsigned lim = PSPLAY_TRAIL_DEPTH, depth = trail->depth; lim > 2 && depth > 2; lim-=2, depth-=2)
{
PSplaynode node = *trail->trail [trailidx (depth)];
PSplaynode parent = *trail->trail [trailidx (depth-1)];
PSplaynode grandparent = *trail->trail [trailidx (depth-2)];
unsigned r = PSPLAY_FORMULA;
TRACE (psplay, "r is %u", r);
if (parent == grandparent->left)
{
TRACE (psplay, "ZIG..");
if (node == parent->left)
{
TRACE (psplay, "..ZIG");
if (r < PSPLAY_PROB_ZIGZIG)
{
TRACE (psplay, "BREAK");
return;
}
grandparent->left = parent->right;
parent->right = grandparent;
parent->left = node->right;
node->right = parent;
}
else
{
TRACE (psplay, "..ZAG");
if (r < PSPLAY_PROB_ZIGZAG)
{
TRACE (psplay, "BREAK");
return;
}
parent->right = node->left;
node->left = parent;
grandparent->left = node->right;
node->right = grandparent;
}
}
else
{
TRACE (psplay, "ZAG..");
if (node == parent->left)
{
TRACE (psplay, "..ZIG");
if (r < PSPLAY_PROB_ZIGZAG)
{
TRACE (psplay, "BREAK");
return;
}
parent->left = node->right;
node->right = parent;
grandparent->right = node->left;
node->left = grandparent;
}
else
{
TRACE (psplay, "..ZAG");
if (r < PSPLAY_PROB_ZIGZIG)
{
TRACE (psplay, "BREAK");
return;
}
grandparent->right = parent->left;
parent->left = grandparent;
parent->right = node->left;
node->left = parent;
}
}
*trail->trail [trailidx (depth-2)] = node;
}
}
PSplaynode
psplay_insert (PSplay self, PSplaynode node, int splayfactor)
{
TRACE (psplay);
PSplaynode n = self->tree;
struct psplaytrail trail;
trail.dir = 0;
trail.depth = 0;
trail.trail [0] = &self->tree;
if (!n)
self->tree = node;
else
{
while (n != node)
{
int c;
c = self->cmp (self->key (node), self->key (n));
++trail.depth;
if (c < 0)
{
--trail.dir;
if (!n->left)
n->left = node;
trail.trail [trailidx (trail.depth)] = &n->left;
n = n->left;
}
else if (c > 0)
{
++trail.dir;
if (!n->right)
n->right = node;
trail.trail [trailidx (trail.depth)] = &n->right;
n = n->right;
}
else
{
TODO ("policy for multiple entered items (before, after, fail, replace)");
return NULL;
}
}
}
++self->elem_cnt;
if (self->elem_cnt >= 1<<self->log2) ++self->log2;
if (splayfactor && trail.depth > 2)
psplay_splay (self, &trail, splayfactor);
return node;
}
PSplaynode
psplay_find (PSplay self, const void* key, int splayfactor)
{
TRACE (psplay);
PSplaynode node = self->tree;
struct psplaytrail trail;
trail.dir = 0;
trail.depth = 0;
trail.trail [0] = &self->tree;
while (node)
{
int c;
c = self->cmp (key, self->key (node));
++trail.depth;
if (c < 0)
{
--trail.dir;
trail.trail [trailidx (trail.depth)] = &node->left;
node = node->left;
}
else if (c > 0)
{
++trail.dir;
trail.trail [trailidx (trail.depth)] = &node->right;
node = node->right;
}
else
{
self->found_parent = trail.trail [trailidx (--trail.depth)];
break;
}
}
if (node && splayfactor && trail.depth > 2)
psplay_splay (self, &trail, splayfactor);
return node;
}
PSplaynode
psplay_remove (PSplay self, PSplaynode node)
{
TRACE (psplay);
if (!node) return NULL;
PSplaynode* r = self->found_parent;
while (*r != node)
{
if (!psplay_find (self, self->key (node), 0))
{
WARN (psplay, "node %p is not in splay tree %p", node, self);
return NULL;
}
r = self->found_parent;
}
if (!node->left)
*r = node->right;
else if (!node->right)
*r = node->left;
else
{
PSplaynode i, iparent = NULL;
if (psplay_fast_prng()&1) /* 50% probability removing left or right wards */
{
for (i = node->left; i->right; iparent = i, i = i->right);
if (iparent)
iparent->right = i->left;
if (node->left != i)
i->left = node->left;
i->right = node->right;
}
else
{
for (i = node->right; i->left; iparent = i, i = i->left);
if (iparent)
iparent->left = i->right;
if (node->right != i)
i->right = node->right;
i->left = node->left;
}
*r = i;
}
--self->elem_cnt;
if (self->elem_cnt < 1<<self->log2) --self->log2;
return node;
}
PSplaynode
psplay_remove_key (PSplay self, void* key)
{
return psplay_remove (self, psplay_find (self, key, 0));
}
void
psplay_delete_node (PSplay self, PSplaynode node)
{
if (node)
self->delete (psplay_remove (self, node));
}
void
psplay_delete_key (PSplay self, void* key)
{
PSplaynode node = psplay_find (self, key, 0);
psplay_delete_node (self, node);
}
const psplay_delete_fn PSPLAY_CONT = (psplay_delete_fn)0x0;
const psplay_delete_fn PSPLAY_STOP = (psplay_delete_fn)0x1;
const psplay_delete_fn PSPLAY_REMOVE = (psplay_delete_fn)0x2;
static int
psplay_handle (PSplay self, PSplaynode node, psplay_delete_fn res)
{
if (res == PSPLAY_CONT)
return 1;
if (res == PSPLAY_STOP)
;
else if (res == PSPLAY_REMOVE)
{
psplay_remove (self, node);
if (self->delete)
self->delete (node);
}
else
{
psplay_remove (self, node);
res (node);
}
return 0;
}
int
psplay_walk (PSplay self, PSplaynode node, psplay_action_fn action, int level, void* data)
{
if (!self->tree)
return 1;
if (!node)
node = self->tree;
psplay_delete_fn res;
res = action (node, PSPLAY_PREORDER, level, data);
if (!psplay_handle (self, node, res))
return 0;
if (node->left)
if (!psplay_walk (self, node->left, action, level+1, data))
return 0;
res = action (node, PSPLAY_INORDER, level, data);
if (!psplay_handle (self, node, res))
return 0;
if (node->right)
if (!psplay_walk (self, node->right, action, level+1, data))
return 0;
res = action (node, PSPLAY_POSTORDER, level, data);
if (!psplay_handle (self, node, res))
return 0;
return 1;
}
static psplay_delete_fn
psplay_print_node (PSplaynode node, const enum psplay_order_enum which, int level, void* data)
{
FILE* fh = data;
static char* sp = " ";
if (level>40)
{
if (which == PSPLAY_PREORDER)
fprintf (fh, "%s ...\n", sp);
return PSPLAY_CONT;
}
switch (which)
{
case PSPLAY_PREORDER:
fprintf (fh, "%s%p\n", sp+40-level, node);
if (node->left)
fprintf (fh, "%sleft %p\n", sp+40-level, node->left);
break;
case PSPLAY_INORDER:
if (node->right)
fprintf (fh, "%sright %p\n", sp+40-level, node->right);
break;
case PSPLAY_POSTORDER:
break;
}
return PSPLAY_CONT;
}
void
psplay_dump (PSplay self, FILE* dest)
{
fprintf (dest, "root %p\n", self->tree);
psplay_walk (self, NULL, psplay_print_node, 0, dest);
}
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

292
src/lib/psplay.h Normal file
View file

@ -0,0 +1,292 @@
/*
psplay.h - probabilistic splay tree
Copyright (C)
2004, 2005, 2006, Christian Thaeter <chth@gmx.net>
Copyright (C) Lumiera.org
2007, 2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef PSPLAY_H
#define PSPLAY_H
#include <stdint.h>
#include <stdio.h>
/**
* @file
* Probabilistic splay trees
* A splay trees is self-optimizing (in contrast to self-balancing) datastructure.
* We introduce here a probabilistic bottom up approach which reduces the splay costs.
* Without affecting the performance. The randomization gives also some insurance that
* worst case situations are extremely unlikely.
* Tree nodes are very small (just 2 pointers) and are intrusively placed into the users
* datastructure.
*/
/**
* Type and handle for a psplay tree node
* This node have to be placed inside users data.
*/
typedef struct psplaynode_struct psplaynode;
typedef psplaynode* PSplaynode;
struct psplaynode_struct
{
PSplaynode left;
PSplaynode right;
};
/**
* Function use to compare keys
* @param a first key
* @param b second key
* @return shall return -1/0/1 when a is less than/equal to/biggier than b.
*/
typedef int (*psplay_cmp_fn)(const void* a, const void* b);
/**
* Destructor for user defined data
* Called when an element got removed from a splay tree.
* @param node pointer to the intrusive node inside the users datastructure
* The user is responsible for casting 'node' back to his real datastructure (maybe with OFFSET_OF()),
* free all resources associated with it and finally free the datastructure itself.
*/
typedef void (*psplay_delete_fn)(PSplaynode node);
/**
* Retrieve the key from a user datastructure
* @param node pointer to the intrusive node inside the users datastructure
* This functiom must return a pointer to the key under which the user stores his data.
*/
typedef const void* (*psplay_key_fn)(const PSplaynode node);
/**
* Type and handle for a psplay root structure
* This structure shall be treated opaque, its only defined in the header to allow
* one to integrate it directly instead referencing it.
*/
typedef struct psplay_struct psplay;
typedef psplay* PSplay;
struct psplay_struct
{
PSplaynode tree; /* the tree */
PSplaynode* found_parent; /* maybe direct parent of last found node, used for fast remove */
psplay_cmp_fn cmp;
psplay_key_fn key;
psplay_delete_fn delete;
size_t elem_cnt;
unsigned log2; /* roughly log2 of the elem_cnt*/
};
/**
* Number of elements in tree
* @param self pointer to the tree
* @return number of elements
*/
static inline size_t
psplay_nelements (PSplay self)
{
return self->elem_cnt;
};
/**
* Initialize a splay tree
* @param self pointer to the psplay structure
* @param cmp user supplied compare function
* @param key user supplied function to retrieve a key
* @param delete user supplied destructor function or NULL if no destructor is necessary
* @return self
*/
PSplay
psplay_init (PSplay self, psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete);
/**
* Destroy a splay tree
* Frees all elements and associated resources of a splay tree
* @param self pointer to the psplay structure
* @return self
*/
PSplay
psplay_destroy (PSplay self);
/**
* Allocate a splay tree
* @param cmp user supplied compare function
* @param key user supplied function to retrieve a key
* @param delete user supplied destructor function or NULL if no destructor is necessary
* @return allcoated splay tree or NULL on error
*/
PSplay
psplay_new (psplay_cmp_fn cmp, psplay_key_fn key, psplay_delete_fn delete);
/**
* Delete a splay tree
* Frees all elements and associated resources of a splay tree and then itseld
* @param self pointer to the psplay structure
*/
void
psplay_delete (PSplay self);
/**
* Initialize a splay tree node
* The user has to place this nodes within his datastructure and must
* initialize them before using them.
* @param self pointer to the node to be initialized
* @return self
*/
PSplaynode
psplaynode_init (PSplaynode self);
/**
* Insert a element into a splay tree
* @param self pointer to the splay tree
* @param node pointer to the node to be inserted
* @param splayfactor weight for the probabilistic splaying,
* 0 disables the splaying, 100 is the expected normal value
* use 100 when in doubt
* @return self or NULL when a node with same key already in the tree
*/
PSplaynode
psplay_insert (PSplay self, PSplaynode node, int splayfactor);
/**
* Find a element in a splay tree
* @param self pointer to the splay tree
* @param key pointer to the key to be searched
* @param splayfactor weight for the probabilistic splaying,
* 0 disables the splaying, 100 is the expected normal value
* @return found node or NULL if the key was not found in the tree
*/
PSplaynode
psplay_find (PSplay self, const void* key, int splayfactor);
/**
* Remove a node from a splay tree
* @param self pointer to the splay tree
* @param node node to be removed
* @return pointer to the removed node
* removal is optimized for the case where one call it immediately after one did a
* psplay_find() as last operation on that tree
*/
PSplaynode
psplay_remove (PSplay self, PSplaynode node);
/**
* Remove a node by key from a splay tree
* @param self pointer to the splay tree
* @param key key of the node to be removed
* @return pointer to the removed node
*/
PSplaynode
psplay_remove_key (PSplay self, void* key);
/**
* Delete a node from a splay tree
* @param self pointer to the splay tree
* @param node node to be removed
* Calls the registered delete handler, frees all resources.
*/
void
psplay_delete_node (PSplay self, PSplaynode node);
/**
* Delete a node by key from a splay tree
* @param self pointer to the splay tree
* @param key key of the node to be removed
* Calls the registered delete handler, frees all resources.
*/
void
psplay_delete_key (PSplay self, void* key);
enum psplay_order_enum
{
PSPLAY_PREORDER,
PSPLAY_INORDER,
PSPLAY_POSTORDER
};
/**
* Traverse a splay tree
* Traversing a tree calls a user supplied action three times
* An 'action' must not alter the tree itself but it can indicate aborting the tree traversal and
* how the current node is handled by its return value.
* @param node pointer to the currently traversed node
* @param which state of the traversal:
* PSPLAY_PREORDER before visiting the left subtree,
* PSPLAY_INORDER after visiting the left subtree and before the right subtree
* PSPLAY_POSTORDER finally after visiting the right subtree.
* Example: For to traverse the tree in order action would only handle PSPLAY_INORDER.
* This action shall return PSPLAY_CONT when the traversal of the tree shall continue.
* @param level depth of the node in the tree
* @param data user supplied data which is transparently passed around
* @return a pointer to a function which indicates how to proceed, there are three special
* return values predefined:
* PSPLAY_CONT - continue with the traversal
* PSPLAY_STOP - stop the traversal
* PSPLAY_REMOVE - stops the traversal and removes the current node, calling the delete handler
* any other psplay_delete_fn - stops the traversal and removes the current node, calling the returned delete handler with it
*/
typedef psplay_delete_fn (*psplay_action_fn)(PSplaynode node, const enum psplay_order_enum which, int level, void* data);
extern const psplay_delete_fn PSPLAY_CONT;
extern const psplay_delete_fn PSPLAY_STOP;
extern const psplay_delete_fn PSPLAY_REMOVE;
/**
* Start a tree traversal
* @param self the tree to be traversed
* @param node pointer to root node where traversal shall start, use NULL for the whole tree
* @param action handler function as defined above
* @param level initial value for the level
* @param data user supplied data which is transparently passed to the action
* @return 0 when the tree traversal got aborted (by anything but PSPLAY_CONT as action handler return)
* 1 when the whole tree was traversed successfully
*/
int
psplay_walk (PSplay self, PSplaynode node, psplay_action_fn action, int level, void* data);
void
psplay_dump (PSplay self, FILE* dest);
#endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -1,223 +0,0 @@
/*
references.c - strong and weak references
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "lib/references.h"
#include "lib/safeclib.h"
/**
* @file
* Strong and Weak references
* Strong references keep some object alive while they existing
* Weak references become invalidated when the referenced object gets destroyed
*
* Thread safety: references protect their internal operations with a mutex (optimization using futex may come in future)
* while operations on the reference itself (initialization, destruction, strengthen, weaken) and on the referenced object (get)
* should be protected from elsewhere.
*/
/**
* Construct an initial strong reference from an object.
* For every object which should be managed with references you need to construct an initial strong reference
* which then will be used to initialize all further references.
* @param self pointer to the reference to be initialized
* @param obj pointer to the object being referenced
* @param dtor destructor function which will be called on obj when the last strong reference gets deleted
* @return self as given
*/
LumieraReference
lumiera_reference_strong_init_once (LumieraReference self, void* obj, void (*dtor)(void*))
{
LumieraReftarget target = lumiera_malloc (sizeof(lumiera_reftarget));
target->object = obj;
target->dtor = dtor;
target->strong_cnt = 1;
target->weak_cnt = 0;
lumiera_mutex_init (&target->lock);
self->object = obj;
self->target = target;
return self;
}
/**
* Destroy a reference.
* All references need to be destroyed when not used any more.
* When the last strong reference gets destroyed, the object's destructor is called.
* Remaining weak references stay invalidated then until they get destroyed too.
* @param self reference to be destroyed
* @return self as given
* destroying a reference is not thread safe as far as 2 threads try to concurrently destroy it!
*/
LumieraReference
lumiera_reference_destroy (LumieraReference self)
{
LumieraReftarget target = self->target;
/* defensive, lets detect errors if anything still tries to use this reference */
self->target = NULL;
lumiera_mutexacquirer lock;
lumiera_mutexacquirer_init_mutex (&lock, &target->lock, LUMIERA_LOCKED);
if (self->object)
{
/* strong reference */
if (!--target->strong_cnt)
{
/* was last strong reference */
if (target->dtor)
target->dtor (target->object);
target->object = NULL;
if (!target->weak_cnt)
{
/* no weak refs either, destroy it */
lumiera_mutexacquirer_unlock (&lock);
lumiera_mutex_destroy (&target->lock);
free (target);
return self;
}
}
}
else
{
/* weak reference */
if (!--target->weak_cnt && !target->strong_cnt)
{
/* was last weak reference, and no strong refs left */
lumiera_mutexacquirer_unlock (&lock);
lumiera_mutex_destroy (&target->lock);
free (target);
return self;
}
}
lumiera_mutexacquirer_unlock (&lock);
return self;
}
/**
* Copy construct a reference as strong reference
* @param source reference to copy
* @return self as strong reference (always for strong references) or NULL if source is an invalidated weak reference,
* in the later case the reference is constructed as weak reference barely to allow it be destroyed
*/
LumieraReference
lumiera_reference_strong_init (LumieraReference self, LumieraReference source)
{
lumiera_mutexacquirer lock;
lumiera_mutexacquirer_init_mutex (&lock, &source->target->lock, LUMIERA_LOCKED);
self->object = source->target->object;
self->target = source->target;
if (self->object)
{
++self->target->strong_cnt;
}
else
{
++self->target->weak_cnt;
self = NULL;
}
lumiera_mutexacquirer_unlock (&lock);
return self;
}
/**
* Copy construct a reference as weak reference
* @param source reference to copy
* @return self (always for strong references) or NULL if self is an invalidated weak reference
*/
LumieraReference
lumiera_reference_weak_init (LumieraReference self, LumieraReference source)
{
lumiera_mutexacquirer lock;
lumiera_mutexacquirer_init_mutex (&lock, &source->target->lock, LUMIERA_LOCKED);
self->object = NULL;
self->target = source->target;
++self->target->weak_cnt;
if (!self->target->object)
/* already invalidated */
self = NULL;
lumiera_mutexacquirer_unlock (&lock);
return self;
}
/**
* turn a (strong) reference into a weak reference
* Weaken a reference may remove its last strong reference and thus destroy the object
* do nothing if the referene is already weak
* @return self or NULL if the final strong reference got removed,
*/
LumieraReference
lumiera_reference_weaken (restrict LumieraReference self)
{
/* is this a strong reference? */
if (self->object)
{
lumiera_mutexacquirer lock;
lumiera_mutexacquirer_init_mutex (&lock, &self->target->lock, LUMIERA_LOCKED);
self->object = NULL;
++self->target->weak_cnt;
if (!--self->target->strong_cnt)
{
if (self->target->dtor)
self->target->dtor (self->target->object);
self->target->object = NULL;
self = NULL;
}
lumiera_mutexacquirer_unlock (&lock);
}
return self;
}
/**
* turn a (weak) reference into a strong reference
* only references of object which are not already destroyed can be strengthened
* @return self when successful, NULL when the object was already destroyed, 'self' stays a dead weak reference in that case
*/
LumieraReference
lumiera_reference_strengthen (LumieraReference self)
{
/* is this a weak reference? */
if (!self->object)
{
lumiera_mutexacquirer lock;
lumiera_mutexacquirer_init_mutex (&lock, &self->target->lock, LUMIERA_LOCKED);
if (self->target->object)
{
self->object = self->target->object;
--self->target->weak_cnt;
++self->target->strong_cnt;
}
else
self = NULL;
lumiera_mutexacquirer_unlock (&lock);
}
return self;
}

View file

@ -1,106 +0,0 @@
/*
references.h - strong and weak references
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LUMIERA_REFERENCES_H
#define LUMIERA_REFERENCES_H
#include <nobug.h>
/**
* @file
* Strong and Weak references, header.
*/
typedef struct lumiera_reference_struct lumiera_reference;
typedef lumiera_reference* LumieraReference;
#include "lib/error.h"
#include "lib/mutex.h"
/* Implementation detail */
struct lumiera_reftarget_struct
{
void* object;
void (*dtor)(void*);
unsigned strong_cnt; /*when strong becomes 0 obj is destroyed, if weak is 0 destroy target too*/
unsigned weak_cnt; /*when weak becomes 0 and !obj and lock strong is 0, destroy target */
lumiera_mutex lock;
};
typedef struct lumiera_reftarget_struct lumiera_reftarget;
typedef lumiera_reftarget* LumieraReftarget;
/**
* A reference pointing to some other object
*/
struct lumiera_reference_struct
{
void* object; /*set for strong, NULL for weak*/
LumieraReftarget target;
};
#define lumiera_reference \
lumiera_reference NOBUG_CLEANUP(lumiera_reference_ensuredestroyed)
/* helper function for nobug */
static inline void
lumiera_reference_ensuredestroyed (LumieraReference self)
{
ENSURE (!self->target, "forgot to destroy reference");
}
LumieraReference
lumiera_reference_strong_init_once (LumieraReference self, void* obj, void (*dtor)(void*));
LumieraReference
lumiera_reference_destroy (LumieraReference self);
/**
* Get object from a strong reference.
* @return pointer to object, NULL if applied to a weak reference
*/
static inline void*
lumiera_reference_get (LumieraReference self)
{
ENSURE (self->target, "illegal reference (not initialized or already destroyed?)");
return self->object;
}
LumieraReference
lumiera_reference_strong_init (LumieraReference self, LumieraReference source);
LumieraReference
lumiera_reference_weak_init (LumieraReference self, LumieraReference source);
LumieraReference
lumiera_reference_weaken (restrict LumieraReference self);
LumieraReference
lumiera_reference_strengthen (LumieraReference self);
#endif

View file

@ -18,161 +18,52 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <errno.h>
#include "lib/error.h"
#include "lib/rwlock.h"
LUMIERA_ERROR_DEFINE(RWLOCK_AGAIN, "maximum number of readlocks exceed");
LUMIERA_ERROR_DEFINE(RWLOCK_DEADLOCK, "deadlock detected");
LUMIERA_ERROR_DEFINE(RWLOCK_DESTROY, "destroy rwlock");
LUMIERA_ERROR_DEFINE(RWLOCK_UNLOCK, "unlock");
LUMIERA_ERROR_DEFINE(RWLOCK_RLOCK, "rlock");
LUMIERA_ERROR_DEFINE(RWLOCK_WLOCK, "wlock");
LUMIERA_ERROR_DEFINE(RWLOCK_DESTROY, "destroying rwlock");
LUMIERA_ERROR_DEFINE(RWLOCK_UNLOCK, "unlock rwlock failed");
LUMIERA_ERROR_DEFINE(RWLOCK_RDLOCK, "locking rwlock for reading failed");
LUMIERA_ERROR_DEFINE(RWLOCK_WRLOCK, "locking rwlock for writing failed");
/**
* @file
* Read/write locks.
*/
/**
* Initialize a rwlock
* @param self is a pointer to the rwlock to be initialized
* @return self as given
*/
LumieraRWLock
lumiera_rwlock_init (LumieraRWLock self)
lumiera_rwlock_init (LumieraRWLock self, const char* purpose, struct nobug_flag* flag)
{
if (self)
{
pthread_rwlock_init (&self->rwlock, NULL);
NOBUG_RESOURCE_HANDLE_INIT (self->rh);
NOBUG_RESOURCE_ANNOUNCE_RAW (flag, "rwlock", purpose, self, self->rh);
}
return self;
}
/**
* destroy a rwlock
* @param self is a pointer to the rwlock to be initialized
* @return self on success or NULL at error
*/
LumieraRWLock
lumiera_rwlock_destroy (LumieraRWLock self)
lumiera_rwlock_destroy (LumieraRWLock self, struct nobug_flag* flag)
{
if (self)
{
NOBUG_RESOURCE_FORGET_RAW (flag, self->rh);
if (pthread_rwlock_destroy (&self->rwlock))
LUMIERA_DIE (RWLOCK_DESTROY);
}
return self;
}
/**
* initialize a rwlockacquirer state
* @param self rwlockacquirer to be initialized, must be an automatic variable
* @param rwlock associated rwlock
* @param state initial state of the mutex, either LUMIERA_RDLOCKED, LUMIERA_WRLOCKED or LUMIERA_UNLOCKED
* @return self as given or NULL on error
*/
LumieraRWLockacquirer
lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, enum lumiera_lockstate state)
{
REQUIRE (self);
REQUIRE (rwlock);
REQUIRE (state != LUMIERA_LOCKED, "illegal state for rwlock");
self->rwlock = rwlock;
self->state = state;
switch (state)
{
case LUMIERA_RDLOCKED:
switch (pthread_rwlock_rdlock (&rwlock->rwlock))
{
case 0:
break;
case EAGAIN:
lumiera_error_set (LUMIERA_ERROR_RWLOCK_AGAIN);
return NULL;
case EDEADLK:
lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
return NULL;
default:
LUMIERA_DIE (RWLOCK_RLOCK);
}
case LUMIERA_WRLOCKED:
switch (pthread_rwlock_wrlock (&rwlock->rwlock))
{
case 0:
break;
case EDEADLK:
lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
return NULL;
default:
LUMIERA_DIE (RWLOCK_WLOCK);
}
default:
break;
}
return self;
}
/**
* readlock the rwlock.
* must not already be locked
* @param self rwlockacquirer associated with a rwlock
* @return self as given or NULL on error
*/
LumieraRWLockacquirer
lumiera_rwlockacquirer_rdlock (LumieraRWLockacquirer self)
{
REQUIRE (self);
REQUIRE (self->state == LUMIERA_UNLOCKED, "rwlock already locked");
switch (pthread_rwlock_rdlock (&self->rwlock->rwlock))
{
case 0:
break;
case EAGAIN:
lumiera_error_set (LUMIERA_ERROR_RWLOCK_AGAIN);
return NULL;
case EDEADLK:
lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
return NULL;
default:
LUMIERA_DIE (RWLOCK_RLOCK);
}
self->state = LUMIERA_RDLOCKED;
return self;
}
/**
* writelock the rwlock.
* must not already be locked
* @param self rwlockacquirer associated with a rwlock
* @return self as given or NULL on error
*/
LumieraRWLockacquirer
lumiera_rwlockacquirer_wrlock (LumieraRWLockacquirer self)
{
REQUIRE (self);
REQUIRE (self->state == LUMIERA_UNLOCKED, "rwlock already locked");
switch (pthread_rwlock_wrlock (&self->rwlock->rwlock))
{
case 0:
break;
case EDEADLK:
lumiera_error_set (LUMIERA_ERROR_RWLOCK_DEADLOCK);
return NULL;
default:
LUMIERA_DIE (RWLOCK_WLOCK);
}
self->state = LUMIERA_WRLOCKED;
return self;
}
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -29,14 +29,12 @@
#include <pthread.h>
#include <nobug.h>
#include "lib/locking.h"
LUMIERA_ERROR_DECLARE(RWLOCK_AGAIN);
LUMIERA_ERROR_DECLARE(RWLOCK_DEADLOCK);
LUMIERA_ERROR_DECLARE(RWLOCK_DESTROY);
LUMIERA_ERROR_DECLARE(RWLOCK_UNLOCK);
LUMIERA_ERROR_DECLARE(RWLOCK_RLOCK);
LUMIERA_ERROR_DECLARE(RWLOCK_WLOCK);
LUMIERA_ERROR_DECLARE(RWLOCK_RDLOCK);
LUMIERA_ERROR_DECLARE(RWLOCK_WRLOCK);
/**
* @file
@ -44,6 +42,56 @@ LUMIERA_ERROR_DECLARE(RWLOCK_WLOCK);
*/
/**
* Read locked section.
*/
#define LUMIERA_RDLOCK_SECTION(nobugflag, rwlck) \
for (lumiera_rwlockacquirer NOBUG_CLEANUP(lumiera_rwlockacquirer_ensureunlocked) lumiera_rwlock_section_ = {(LumieraRWLock)1}; \
lumiera_rwlock_section_.rwlock;) \
for ( \
({ \
lumiera_rwlock_section_.rwlock = (rwlck); \
NOBUG_RESOURCE_HANDLE_INIT (lumiera_rwlock_section_.rh); \
RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire rwlock for reading", &lumiera_rwlock_section_, \
NOBUG_RESOURCE_EXCLUSIVE, lumiera_rwlock_section_.rh); \
if (pthread_rwlock_rdlock (&(rwlck)->rwlock)) LUMIERA_DIE (RWLOCK_RDLOCK); \
}); \
lumiera_rwlock_section_.rwlock; \
({ \
if (lumiera_rwlock_section_.rwlock) \
{ \
pthread_rwlock_unlock (&lumiera_rwlock_section_.rwlock->rwlock); \
lumiera_rwlock_section_.rwlock = NULL; \
RESOURCE_LEAVE(nobugflag, lumiera_rwlock_section_.rh); \
} \
}))
/**
* Write locked section.
*/
#define LUMIERA_WRLOCK_SECTION(nobugflag, rwlck) \
for (lumiera_rwlockacquirer NOBUG_CLEANUP(lumiera_rwlockacquirer_ensureunlocked) lumiera_rwlock_section_ = {(LumieraRWLock)1}; \
lumiera_rwlock_section_.rwlock;) \
for ( \
({ \
lumiera_rwlock_section_.rwlock = (rwlck); \
NOBUG_RESOURCE_HANDLE_INIT (lumiera_rwlock_section_.rh); \
RESOURCE_ENTER (nobugflag, (rwlck)->rh, "acquire rwlock for reading", &lumiera_rwlock_section_, \
NOBUG_RESOURCE_EXCLUSIVE, lumiera_rwlock_section_.rh); \
if (pthread_rwlock_wrlock (&(rwlck)->rwlock)) LUMIERA_DIE (RWLOCK_WRLOCK); \
}); \
lumiera_rwlock_section_.rwlock; \
({ \
if (lumiera_rwlock_section_.rwlock) \
{ \
pthread_rwlock_unlock (&lumiera_rwlock_section_.rwlock->rwlock); \
lumiera_rwlock_section_.rwlock = NULL; \
RESOURCE_LEAVE(nobugflag, lumiera_rwlock_section_.rh); \
} \
}))
/**
* RWLock.
*
@ -51,17 +99,27 @@ LUMIERA_ERROR_DECLARE(RWLOCK_WLOCK);
struct lumiera_rwlock_struct
{
pthread_rwlock_t rwlock;
RESOURCE_HANDLE (rh);
};
typedef struct lumiera_rwlock_struct lumiera_rwlock;
typedef lumiera_rwlock* LumieraRWLock;
/**
* Initialize a rwlock
* @param self is a pointer to the rwlock to be initialized
* @return self as given
*/
LumieraRWLock
lumiera_rwlock_init (LumieraRWLock self);
lumiera_rwlock_init (LumieraRWLock self, const char* purpose, struct nobug_flag* flag);
/**
* destroy a rwlock
* @param self is a pointer to the rwlock to be initialized
* @return self on success or NULL at error
*/
LumieraRWLock
lumiera_rwlock_destroy (LumieraRWLock self);
lumiera_rwlock_destroy (LumieraRWLock self, struct nobug_flag* flag);
@ -72,7 +130,7 @@ lumiera_rwlock_destroy (LumieraRWLock self);
struct lumiera_rwlockacquirer_struct
{
LumieraRWLock rwlock;
enum lumiera_lockstate state;
RESOURCE_HANDLE (rh);
};
typedef struct lumiera_rwlockacquirer_struct lumiera_rwlockacquirer;
typedef struct lumiera_rwlockacquirer_struct* LumieraRWLockacquirer;
@ -81,39 +139,15 @@ typedef struct lumiera_rwlockacquirer_struct* LumieraRWLockacquirer;
static inline void
lumiera_rwlockacquirer_ensureunlocked (LumieraRWLockacquirer self)
{
ENSURE (self->state == LUMIERA_UNLOCKED, "forgot to unlock the rwlock mutex");
}
/* override with a macro to use the cleanup checker */
#define lumiera_rwlockacquirer \
lumiera_rwlockacquirer NOBUG_CLEANUP(lumiera_rwlockacquirer_ensureunlocked)
LumieraRWLockacquirer
lumiera_rwlockacquirer_init (LumieraRWLockacquirer self, LumieraRWLock rwlock, enum lumiera_lockstate state);
LumieraRWLockacquirer
lumiera_rwlockacquirer_rdlock (LumieraRWLockacquirer self);
LumieraRWLockacquirer
lumiera_rwlockacquirer_wrlock (LumieraRWLockacquirer self);
/**
* release rwlock.
* a rwlockacquirer must be unlocked before leaving scope
* @param self rwlockacquirer associated with a rwlock variable
*/
static inline void
lumiera_rwlockacquirer_unlock (LumieraRWLockacquirer self)
{
REQUIRE (self);
REQUIRE (self->state != LUMIERA_UNLOCKED, "rwlock was not locked");
if (pthread_rwlock_unlock (&self->rwlock->rwlock))
LUMIERA_DIE (RWLOCK_UNLOCK);
self->state = LUMIERA_UNLOCKED;
ENSURE (!self->rwlock, "forgot to unlock rwlock");
}
#endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -18,27 +18,19 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "error.h"
#include "lib/error.h"
#include "lib/safeclib.h"
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdint.h>
#include <stdarg.h>
#include <nobug.h>
/**
* @file
* Portable and safe wrapers around some clib functions and some tools
*/
LUMIERA_ERROR_DEFINE (NO_MEMORY, "Out of Memory!");
/**
* Allocate memory.
* always succeeds or dies
* @param size memory to be allocated
* @return pointer to the allocated memory
*/
void*
lumiera_malloc (size_t size)
{
@ -49,13 +41,6 @@ lumiera_malloc (size_t size)
}
/**
* Allocate cleared memory for an array.
* always succeeds or dies
* @param n number of elements
* @param size memory to be allocated
* @return pointer to the allocated memory
*/
void*
lumiera_calloc (size_t n, size_t size)
{
@ -66,13 +51,6 @@ lumiera_calloc (size_t n, size_t size)
}
/**
* Duplicate a C string.
* always succeeds or dies
* @param str string to be copied
* @param len maximal length to be copied
* @return pointer to the new string, "" if NULL was passed as str
*/
char*
lumiera_strndup (const char* str, size_t len)
{
@ -88,14 +66,6 @@ lumiera_strndup (const char* str, size_t len)
}
/**
* Compare two C strings.
* Handles NULL pointers as "", shortcut for same addresses
* @param a first string for comparsion
* @param b second string for comparsion
* @param len maximal length for the comparsion
* @return 0 if the strings are identical, -1 if smaller 1 if bigger.
*/
int
lumiera_strncmp (const char* a, const char* b, size_t len)
{
@ -103,12 +73,6 @@ lumiera_strncmp (const char* a, const char* b, size_t len)
}
/**
* check 2 strings for identity.
* @param a first string for comparsion
* @param b second string for comparsion
* @return 1 when the strings are the the same, 0 if not.
*/
int
lumiera_streq (const char* a, const char* b)
{
@ -116,11 +80,6 @@ lumiera_streq (const char* a, const char* b)
}
/**
* Round robin temporary buffers.
* This provides 64 buffers per thread which are recycled with each use.
* The idea here is to have fast buffers for temporal data without need for explicit heap management.
*/
struct lumiera_tmpbuf_struct
{
void* buffers[64];
@ -144,13 +103,10 @@ static void
lumiera_tmpbuf_init (void)
{
pthread_key_create (&lumiera_tmpbuf_tls_key, lumiera_tmpbuf_destroy);
TODO ("register an atexit() handler to free tmpbufs");
}
/**
* free all buffers associated with this thread.
* This function is called automatically, usually one doesnt need to call it.
*/
void
lumiera_tmpbuf_freeall (void)
{
@ -160,17 +116,12 @@ lumiera_tmpbuf_freeall (void)
{
pthread_setspecific (lumiera_tmpbuf_tls_key, NULL);
for (int idx = 0; idx < 64; ++idx)
free (buf->buffers[idx]);
free (buf);
lumiera_free (buf->buffers[idx]);
lumiera_free (buf);
}
}
/**
* Query a thread local buffer.
* @param size minimal needed size for the buffer
* @return the buffer
*/
void*
lumiera_tmpbuf_provide (size_t size)
{
@ -184,7 +135,7 @@ lumiera_tmpbuf_provide (size_t size)
if (buf->sizes[buf->idx] < size || buf->sizes[buf->idx] > 8*size)
{
free (buf->buffers[buf->idx]);
lumiera_free (buf->buffers[buf->idx]);
buf->sizes[buf->idx] = (size+4*sizeof(long)) & ~(4*sizeof(long)-1);
buf->buffers[buf->idx] = lumiera_malloc (buf->sizes[buf->idx]);
}
@ -223,3 +174,49 @@ lumiera_tmpbuf_snprintf (size_t size, const char* fmt, ...)
return buf;
}
char*
lumiera_tmpbuf_strcat3 (const char* str1, size_t str1_len,
const char* str2, size_t str2_len,
const char* str3, size_t str3_len)
{
return lumiera_tmpbuf_snprintf (SIZE_MAX, "%.*s%s%.*s%s%.*s",
str1?str1_len:0, str1?str1:"", str1?".":"",
str2?str2_len:0, str2?str2:"",
str3?".":"", str3?str3_len:0, str3?str3:"");
}
char*
lumiera_tmpbuf_tr (const char* in, const char* from, const char* to, const char* def)
{
REQUIRE (strlen (from) == strlen (to), "from and to character set must have equal length");
char* ret = lumiera_tmpbuf_strndup (in, SIZE_MAX);
char* wpos;
char* rpos;
for (wpos = rpos = ret; *rpos; ++rpos, ++wpos)
{
char* found = strchr (from, *rpos);
if (found)
*wpos = to[found-from];
else if (def)
{
if (*def)
*wpos = *def;
else
{
++rpos;
if (!*rpos)
break;
}
}
else
return NULL;
}
*wpos = '\0';
return ret;
}

View file

@ -50,6 +50,18 @@ void*
lumiera_calloc (size_t n, size_t size);
/**
* Free previously allocated memory.
* @param mem pointer to the memory block obtained by lumiera_malloc or lumiera_calloc
*/
static inline void
lumiera_free (void* mem)
{
/* for now only a alias, might change in future */
free (mem);
}
/**
* Duplicate a C string.
* always succeeds or dies
@ -123,3 +135,33 @@ lumiera_tmpbuf_strndup (const char* src, size_t size);
char*
lumiera_tmpbuf_snprintf (size_t size, const char* fmt, ...);
/**
* Concat up to 3 strings in a tmpbuf.
* @param str1 first string to concat or NULL
* @param str1_len how much of the first string shall be used
* @param str2 second string to concat or NULL
* @param str2_len how much of the second string shall be used
* @param str3 third string to concat or NULL
* @param str3_len how much of the third string shall be used
* @return temporary buffer containing the constructed of the string
*/
char*
lumiera_tmpbuf_strcat3 (const char* str1, size_t str1_len,
const char* str2, size_t str2_len,
const char* str3, size_t str3_len);
/**
* Translates characters in a string, similar to the shell 'tr' utility
* @param in input string to be translated
* @param from source character set
* @param to destination character set
* @param def default destination character when a character is not in the source set,
* when NULL then translation will abort on unknown characters and return NULL,
* when "" then unknown characters will be removed
* when set to a single character string, unknown characters will be replaced with this string
* @return temporary buffer containing the constructed of the string
*/
char*
lumiera_tmpbuf_tr (const char* in, const char* from, const char* to, const char* def);

View file

@ -1,95 +0,0 @@
/*
uuid - Universal unique identifiers
Copyright (C) CinelerraCV
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "lib/uuid.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
void
lumiera_uuid_set_ptr (lumiera_uuid* uuid, void* ptr)
{
memset (uuid, 0, 16);
*(void**)uuid = ptr;
}
void*
lumiera_uuid_ptr_get (lumiera_uuid* uuid)
{
return *(void**)uuid;
}
void
lumiera_uuid_gen (lumiera_uuid* uuid)
{
static int fd = -2;
if (!uuid)
return;
if (fd == -2)
{
fd = open ("/dev/urandom", O_RDONLY);
if (fd == -1)
fd = open ("/dev/random", O_RDONLY);
if (fd >= 0)
fcntl (fd, F_SETFD, FD_CLOEXEC);
else
srand (getpid () + time (NULL));
}
if (fd < 0)
{
for (int i = 0; i < 16; ++i)
((unsigned char*)uuid)[i] = (unsigned char)(rand()>>7);
}
else
{
if (read (fd, uuid, 16) < 0)
abort ();
}
}
void
lumiera_uuid_copy (lumiera_uuid* dest, lumiera_uuid* src)
{
memcpy (dest, src, 16);
}
int
lumiera_uuid_eq (lumiera_uuid* uuida, lumiera_uuid* uuidb)
{
return !memcmp (uuida, uuidb, 16);
}
size_t
lumiera_uuid_hash (lumiera_uuid* uuid)
{
return *(size_t*)uuid;
}

View file

@ -1,67 +0,0 @@
/*
uuid - Universal unique identifiers
Copyright (C) CinelerraCV
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef LUMIERA_UUID_H
#define LUMIERA_UUID_H
#include <stdlib.h>
typedef unsigned char lumiera_uuid[16];
/**
* Retrieve a generic pointer stored in a uuid
*/
void*
lumiera_uuid_ptr_get (lumiera_uuid* uuid);
/**
* Generate a new uuid
*/
void
lumiera_uuid_gen (lumiera_uuid* uuid);
/**
* Store a generic pointer in a uuid
*/
void
lumiera_uuid_set_ptr (lumiera_uuid* uuid, void* ptr);
/**
* Copy an uuid
*/
void
lumiera_uuid_copy (lumiera_uuid* dest, lumiera_uuid* src);
/**
* Test 2 uuid's for equality
*/
int
lumiera_uuid_eq (lumiera_uuid* uuida, lumiera_uuid* uuidb);
/**
* Generate a hashsum over an uuid
*/
size_t
lumiera_uuid_hash (lumiera_uuid* uuid);
#endif

View file

@ -38,7 +38,9 @@ namespace asset
*/
Category::operator string () const
{
char *kinds[6] = { "AUDIO"
typedef const char * const SymID;
SymID kinds[6] = { "AUDIO"
, "VIDEO"
, "EFFECT"
, "CODEC"

View file

@ -53,6 +53,7 @@ namespace mobject
using boost::lambda::var;
namespace // Implementation details //////////////////TODO better a named implementation namespace (avoids warnings on gcc 4.3)
//////////////////////////////////////////////////////////FIXME this is a *real* problem, because this namespace create storage, which it shouldn't
{
struct TableEntry
{

28
src/tool/Makefile.am Normal file
View file

@ -0,0 +1,28 @@
# Copyright (C) Lumiera.org
# 2008 Christian Thaeter <ct@pipapo.org>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
lumitool_srcdir = $(top_srcdir)/src/tool
noinst_PROGRAMS += luidgen
luidgen_CFLAGS = $(CFLAGS) -std=gnu99 -Wall -Werror
luidgen_CPPFLAGS = -I$(top_srcdir)/src/
luidgen_SOURCES = \
$(lumitool_srcdir)/luidgen.c
luidgen_LDADD = liblumi.a

View file

@ -1,8 +1,8 @@
/*
test-locking.c - test locking functions
luidgen.c - generate a lumiera uuid
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
2008 Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@ -19,23 +19,33 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "lib/luid.h"
#include <stdio.h>
#include <string.h>
#include "tests/test.h"
int conditionforgotunlock ();
int mutexforgotunlock ();
/**
* @file
* Generate amd print a Lumiera uid as octal escaped string
*/
TESTS_BEGIN
TEST ("conditionforgotunlock")
int
main (int argc, char** argv)
{
return conditionforgotunlock ();
lumiera_uid luid;
lumiera_uid_gen (&luid);
printf ("\"");
for (int i = 0; i < 16; ++i)
printf ("\\%.3hho", *(((char*)&luid)+i));
printf ("\"\n");
return 0;
}
TEST ("mutexforgotunlock")
{
return mutexforgotunlock ();
}
TESTS_END
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -44,9 +44,11 @@ out: .
out: .
END
TEST "llist_relocate" relocate <<END
END
# not yet tested functions, write tests when needed
PLANNED "llist_relocate"
PLANNED "llist_insertlist_next"
PLANNED "llist_insertlist_prev"
PLANNED "llist_insertafter_range"

View file

@ -1,16 +1,47 @@
TESTING "Locking" ./test-locking
TEST "condition not unlocked asserts" conditionforgotunlock <<END
return: 134
TEST "mutex section" mutexsection <<END
out: mutex locked section 1
out: mutex locked section 2
END
TEST "mutex not unlocked asserts" mutexforgotunlock <<END
return: 134
END
TEST "nested mutex section" nestedmutexsection <<END
out: outer mutex locked section
out: inner mutex locked section
END
TEST "rwlock section" rwlocksection <<END
out: write locked section 1
out: read locked section 2
END
TEST "rwlock not unlocked asserts" rwlockforgotunlock <<END
return: 134
END
TEST "condition not unlocked asserts" conditionforgotunlock <<END
return: 134
END
TEST "condition section" conditionsection <<END
out: condition locked section 1
out: condition locked section 2
END
PLANNED "condition signaling" <<END
END
PLANNED "condition broadcasting" <<END
END

View file

@ -9,9 +9,10 @@ TEST "Allocating some memory" allocation1024 <<END
return: 0
END
# seems that exit codes are not table here, was
# return: 134 before, needs to be fixed with improved testsuite
TEST "Allocation error" allocationtoobig <<END
return: 134
return: 139
END
@ -19,10 +20,36 @@ TEST "string equal check" streq <<END
return: 0
END
TEST "temporary buffers" tmpbuf <<END
return: 0
END
TEST "tr0 success" tr0 123abcABC456 <<END
out: 123ABCABC456
return: 0
END
TEST "tr0 fail" tr0 123abcABC456_ <<END
out: failed
return: 0
END
TEST "tr" tr 123abcABC456_ <<END
out: 123ABCABC456
return: 0
END
TEST "tr_" tr_ 123abc_/?ABC456_ <<END
out: 123ABC___ABC456_
return: 0
END

View file

@ -1,8 +0,0 @@
TESTING "Strong and Weak references" ./test-references
TEST "references basic functionality" basic <<END
out: got: 123
out: destruct: 123
return: 0
END

View file

@ -0,0 +1,27 @@
TESTING "test configuration system" ./test-config
TEST "initializing config system" init <<END
out: initialized
out: destroyed
END
TEST "create configitem with empty line" configitem_simple '' <<END
out: line = ''
END
TEST "create configitem with blank line" configitem_simple ' ' <<END
out: line = ' '
END
TEST "create configitem simple entry" configitem_simple 'foo.bar = baz' <<END
out: line = 'foo.bar = baz'
out: key = 'foo.bar'
out: delim = '='
out: value = ' baz'
END
TEST "key lookup" lookup <<END
END

View file

@ -13,6 +13,18 @@ END
rm ,tmp_testfile
echo testdata > ,tmp_testfile1
echo testdata > ,tmp_testfile2
echo testdata > ,tmp_testfile3
TEST "acquire 3 files" acquire_existing_3files <<END
return: 0
END
rm ,tmp_testfile1
rm ,tmp_testfile2
rm ,tmp_testfile3
TEST "acquire file, creating it" acquire_create <<END
return: 0
END

View file

@ -0,0 +1,192 @@
TESTING "test configuration system" ./test-config
PLANNED "loading configfile, simple" <<END
END
PLANNED "loading configfile, with includes" <<END
END
PLANNED "env var override" <<END
END
PLANNED "lowlevel get" <<END
END
PLANNED "lowlevel set" <<END
END
PLANNED "saving simple configfile" <<END
END
PLANNED "complex saving user file" <<END
END
TEST "number get, default" number_get test.number.1 '1234567890 # comment' <<END
out: 1234567890
END
export LUMIERA_TEST_NUMBER_1=987654321
TEST "number get, env override" number_get test.number.1 '1234567890 # comment' <<END
out: 987654321
END
export LUMIERA_TEST_NUMBER_1=barf
TEST "number get, type error" number_get_nodefault test.number.1 <<END
out: LUMIERA_ERROR_CONFIG_SYNTAX_VALUE:syntax error in value
END
LUMIERA_TEST_NUMBER_1=NAN
TEST "number get, env override, default fallback" number_get test.number.1 '1234567890 # comment' <<END
out: LUMIERA_ERROR_CONFIG_SYNTAX_VALUE:syntax error in value, 1234567890
END
unset LUMIERA_TEST_NUMBER_1
TEST "number get, syntax error" number_get_nodefault test.NUMBER.1 <<END
out: LUMIERA_ERROR_CONFIG_SYNTAX_KEY:syntax error in key
END
TEST "number get, no default, no env" number_get_nodefault test.number.1 <<END
out: LUMIERA_ERROR_CONFIG_NO_ENTRY:no configuration entry
END
PLANNED "number set" <<END
END
PLANNED "real get" <<END
END
PLANNED "real set" <<END
END
export LUMIERA_TEST_STRING="teststring"
TEST "string get" string_get test.string default <<END
out: 'teststring'
END
TEST "string get, default" string_get test.doesntexist default <<END
out: 'default'
END
LUMIERA_TEST_STRING=' no leading and trailing blanks '
TEST "string get, chopped" string_get test.string default <<END
out: 'no leading and trailing blanks'
END
LUMIERA_TEST_STRING=' " quoted string with spaces " "ignored" #comment'
TEST "string get, quoted" string_get test.string default <<END
out: ' quoted string with spaces '
END
LUMIERA_TEST_STRING=' "quoted string "" not ignored" #comment'
TEST "string get, quoted, escaped" string_get test.string default <<END
out: 'quoted string " not ignored'
END
unset LUMIERA_TEST_STRING
TEST "string set" string_set test.string 'foo bar' <<END
out: 'foo bar'
END
export LUMIERA_TEST_WORD=' " double quote is just right'
TEST "word get" word_get test.word default <<END
out: '"'
END
unset LUMIERA_TEST_WORD
PLANNED "word set" <<END
END
PLANNED "bool get" <<END
END
PLANNED "bool set" <<END
END
TEST "create configitem with empty line" configitem_simple_ctor_dtor '' <<END
END
TEST "create configitem with blank line" configitem_simple_ctor_dtor $' \t \t' <<END
END
TEST "create configitem with comment" configitem_simple_ctor_dtor $' #\t comment bla' <<END
END
TEST "create configitem with section" configitem_simple_ctor_dtor $'\t[prefix suffix ] bla' <<END
END
TEST "create configitem with directive" configitem_simple_ctor_dtor $' @include \t\t file \t' <<END
END
TEST "create configitem with configentry" configitem_simple_ctor_dtor $' key \t=\t value' <<END
END
TEST "create configitem with configentry (redirect)" configitem_simple_ctor_dtor $'keya <\t\t keyb ' <<END
END
TEST "check content of configitem with empty line" configitem_simple_content_check $'' << END
END
TEST "check content of configitem with comment" configitem_simple_content_check $'\t #comment bla' << END
out: item->line = ' #comment bla'
END
TEST "check content of configitem with section" configitem_simple_content_check $'[ key.foo suffix.bar ] ' << END
out: item->line = '[ key.foo suffix.bar ] '
out: item->key_size = '7'
out: item->key = 'key.foo suffix.bar ] '
out: item->delim = ' suffix.bar ] '
END
TEST "check content of configitem with directive (without argument)" configitem_simple_content_check $'\t @directive ' << END
out: item->line = ' @directive '
out: item->key_size = '9'
out: item->key = '@directive '
END
TEST "check content of configitem with directive (with argument)" configitem_simple_content_check $'\t @directive \targument' << END
out: item->line = ' @directive argument'
out: item->key_size = '9'
out: item->key = '@directive argument'
out: item->delim = ' argument'
END
TEST "check content of configitem with configentry" configitem_simple_content_check $' \t\t key.foo \t\t=\tbar' << END
out: item->line = ' key.foo = bar'
out: item->key_size = '7'
out: item->key = 'key.foo = bar'
out: item->delim = '= bar'
END
TEST "check content of configitem with configentry (redirect)" configitem_simple_content_check $' \t\t key.foo \t\t<\tkey.bar' << END
out: item->line = ' key.foo < key.bar'
out: item->key_size = '7'
out: item->key = 'key.foo < key.bar'
out: item->delim = '< key.bar'
END

View file

@ -24,10 +24,7 @@ test_error_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_error_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl
check_PROGRAMS += test-locking
test_locking_SOURCES = \
$(tests_srcdir)/locking/test-locking.c \
$(tests_srcdir)/locking/mutex.c \
$(tests_srcdir)/locking/condition.c
test_locking_SOURCES = $(tests_srcdir)/library/test-locking.c
test_locking_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_locking_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
@ -36,20 +33,20 @@ test_llist_SOURCES = $(tests_srcdir)/library/test-llist.c
test_llist_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_llist_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
check_PROGRAMS += test-psplay
test_psplay_SOURCES = $(tests_srcdir)/library/test-psplay.c
test_psplay_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
test_psplay_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
check_PROGRAMS += test-safeclib
test_safeclib_SOURCES = $(tests_srcdir)/library/test-safeclib.c
test_safeclib_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_safeclib_LDADD = $(builddir)/liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
test_safeclib_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
check_PROGRAMS += test-uuid
test_uuid_SOURCES = $(tests_srcdir)/library/test-uuid.c
test_uuid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_uuid_LDADD = $(builddir)/liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
check_PROGRAMS += test-references
test_references_SOURCES = $(tests_srcdir)/library/test-references.c
test_references_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_references_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm -lrt
check_PROGRAMS += test-luid
test_luid_SOURCES = $(tests_srcdir)/library/test-luid.c
test_luid_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_luid_LDADD = liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
check_PROGRAMS += test-filedescriptors
test_filedescriptors_SOURCES = $(tests_srcdir)/backend/test-filedescriptors.c
@ -61,4 +58,9 @@ test_filehandles_SOURCES = $(tests_srcdir)/backend/test-filehandles.c
test_filehandles_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror
test_filehandles_LDADD = liblumibackend.a liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
check_PROGRAMS += test-config
test_config_SOURCES = $(tests_srcdir)/backend/test-config.c
test_config_CPPFLAGS = $(AM_CPPFLAGS) -std=gnu99 -Wall -Werror -I$(top_srcdir)/src/
test_config_LDADD = liblumibackend.a liblumi.a $(NOBUGMT_LUMIERA_LIBS) -ldl -lm
TESTS = $(tests_srcdir)/test.sh

222
tests/backend/test-config.c Normal file
View file

@ -0,0 +1,222 @@
/*
test-config.c - test the config system
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
Simeon Voelkel <simeon_voelkel@arcor.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "lib/safeclib.h"
#include "backend/config.h"
#include "backend/configitem.h"
#include "tests/test.h"
TESTS_BEGIN
TEST ("init")
{
lumiera_config_init ("./");
printf ("initialized\n");
lumiera_config_destroy ();
printf ("destroyed\n");
}
TEST ("configitem_simple")
{
REQUIRE (argv[2]);
lumiera_config_init ("./");
LumieraConfigitem item;
item = lumiera_configitem_new (argv[2]);
ENSURE (item);
printf ("line = '%s'\n", item->line);
if (item->key)
printf ("key = '%.*s'\n", (int)item->key_size, item->key);
if (item->delim)
{
printf ("delim = '%c'\n", *item->delim);
printf ("value = '%s'\n", item->delim+1);
}
lumiera_configitem_delete (item, NULL);
lumiera_config_destroy ();
}
TEST ("lookup")
{
lumiera_config_init ("./");
lumiera_config_lookup lookup;
lumiera_config_lookup_init (&lookup);
LumieraConfigitem item = lumiera_configitem_new ("foo.bar = test");
lumiera_config_lookup_insert (&lookup, item);
LumieraConfigitem found = lumiera_config_lookup_item_find (&lookup, "foo.bar");
ENSURE (found == item);
lumiera_config_lookup_remove (&lookup, found);
ENSURE (!lumiera_config_lookup_item_find (&lookup, "foo.bar"));
lumiera_config_lookup_destroy (&lookup);
lumiera_config_destroy ();
}
TEST ("number_get")
{
REQUIRE (argv[2]);
REQUIRE (argv[3]);
lumiera_config_init ("./");
long long number = 0;
lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "%s = %s", argv[2], argv[3]));
if (!lumiera_config_number_get (argv[2], &number))
printf ("%lld\n", number);
else
printf ("%s, %lld\n", lumiera_error (), number);
lumiera_config_destroy ();
}
TEST ("number_get_nodefault")
{
REQUIRE (argv[2]);
lumiera_config_init ("./");
long long number = 0;
if (!lumiera_config_number_get (argv[2], &number))
printf ("%lld\n", number);
else
printf ("%s\n", lumiera_error ());
lumiera_config_destroy ();
}
TEST ("string_get")
{
REQUIRE (argv[2]);
REQUIRE (argv[3]);
lumiera_config_init ("./");
char* string;
lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "%s = %s", argv[2], argv[3]));
if (!lumiera_config_string_get (argv[2], &string))
printf ("'%s'\n", string);
else
printf ("%s, '%s'\n", lumiera_error (), string);
lumiera_config_destroy ();
}
TEST ("string_set")
{
REQUIRE (argv[2]);
lumiera_config_init ("./");
lumiera_config_string_set (argv[2], &argv[3]);
FIXME ("handle error");
const char* string;
if (!lumiera_config_get (argv[2], &string))
printf ("'%s'\n", string);
else
printf ("%s, '%s'\n", lumiera_error (), string);
lumiera_config_destroy ();
}
TEST ("word_get")
{
REQUIRE (argv[2]);
REQUIRE (argv[3]);
lumiera_config_init ("./");
char* word;
lumiera_config_setdefault (lumiera_tmpbuf_snprintf (SIZE_MAX, "%s = %s", argv[2], argv[3]));
if (!lumiera_config_word_get (argv[2], &word))
printf ("'%s'\n", word);
else
printf ("%s, '%s'\n", lumiera_error (), word);
lumiera_config_destroy ();
}
TEST ("configitem_simple_ctor_dtor")
{
REQUIRE (argv[2]);
lumiera_config_init ("./");
LumieraConfigitem item;
item = lumiera_configitem_new (argv[2]);
lumiera_config_destroy ();
}
TEST ("configitem_simple_content_check")
{
REQUIRE (argv[2]);
lumiera_config_init ("./");
LumieraConfigitem item;
item = lumiera_configitem_new (argv[2]);
if ( item->line )
{
printf("item->line = '%s'\n", item->line);
}
if ( item->key_size )
{
printf("item->key_size = '%zi'\n", item->key_size);
}
if ( item->key )
{
printf("item->key = '%s'\n", item->key);
}
if ( item->delim )
{
printf("item->delim = '%s'\n", item->delim);
}
lumiera_config_destroy ();
}
TESTS_END

View file

@ -57,6 +57,32 @@ TEST ("acquire_existing_again")
return 1;
}
TEST ("acquire_existing_3files")
{
lumiera_backend_init ();
LumieraFiledescriptor descriptor1 = lumiera_filedescriptor_acquire (",tmp_testfile1", LUMIERA_FILE_READONLY);
LumieraFiledescriptor descriptor2 = lumiera_filedescriptor_acquire (",tmp_testfile2", LUMIERA_FILE_READONLY);
LumieraFiledescriptor descriptor3 = lumiera_filedescriptor_acquire (",tmp_testfile3", LUMIERA_FILE_READONLY);
if (descriptor1)
lumiera_filedescriptor_release (descriptor1);
if (descriptor2)
lumiera_filedescriptor_release (descriptor2);
if (descriptor3)
lumiera_filedescriptor_release (descriptor3);
if (descriptor1 && descriptor2 && descriptor3)
{
lumiera_backend_destroy ();
return 0;
}
else
return 1;
}
TEST ("acquire_create")
{
lumiera_backend_init ();

View file

@ -34,7 +34,7 @@ using lumiera::ON_GLOBAL_SHUTDOWN;
* cmd line argument.
* Note: to ease debugging, we don't catch any exceptions.
*/
int main (int argc, char* argv[])
int main (int argc, const char* argv[])
{
util::Cmdline args (argc,argv);
test::TestOption optparser (args);

View file

@ -50,11 +50,11 @@ namespace lumiera
class TestSingletonO
{
int callCnt;
char* typid;
Symbol typid;
format msg;
public:
TestSingletonO(char* ty="TestSingletonO")
TestSingletonO(Symbol ty="TestSingletonO")
: callCnt (0), typid(ty), msg ("%s::doIt() call=%d\n")
{
TRACE (singleton, "ctor %s", typid);

View file

@ -85,7 +85,7 @@ namespace util
*/
void testStandardCmdlineformat()
{
char* fakeArg[3] = {"CMD", "one ", "two"};
const char* fakeArg[3] = {"CMD", "one ", "two"};
Cmdline theCmdline(3, fakeArg);
cout << "Standard Cmdlineformat:" << theCmdline << "\n";
}

View file

@ -1,5 +1,5 @@
/*
test-llist.c - test the linked lis lib
test-llist.c - test the linked list lib
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
@ -185,4 +185,23 @@ TEST ("whiles")
}
TEST ("relocate")
{
llist source;
llist_init (&source);
llist something;
llist_init (&something);
llist_insert_head (&source, &something);
llist target = {NULL,NULL};
target = source;
llist_relocate (&target);
ENSURE (llist_is_head (&target, &something));
}
TESTS_END

View file

@ -0,0 +1,154 @@
/*
test-locking.c - test locking functions
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "tests/test.h"
#include "lib/mutex.h"
#include "lib/condition.h"
#include "lib/rwlock.h"
#include <stdio.h>
#include <string.h>
TESTS_BEGIN
TEST ("mutexsection")
{
lumiera_mutex m;
lumiera_mutex_init (&m, "mutexsection", &NOBUG_FLAG(NOBUG_ON));
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
{
printf ("mutex locked section 1\n");
}
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
{
printf ("mutex locked section 2\n");
}
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
}
TEST ("mutexforgotunlock")
{
lumiera_mutex m;
lumiera_mutex_init (&m, "mutexforgotunlock", &NOBUG_FLAG(NOBUG_ON));
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
{
break; // MUTEX_SECTIONS must not be left by a jump
}
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
}
TEST ("nestedmutexsection")
{
lumiera_mutex m;
lumiera_mutex_init (&m, "m_mutexsection", &NOBUG_FLAG(NOBUG_ON));
lumiera_mutex n;
lumiera_mutex_init (&n, "n_mutexsection", &NOBUG_FLAG(NOBUG_ON));
LUMIERA_MUTEX_SECTION (NOBUG_ON, &m)
{
printf ("outer mutex locked section\n");
LUMIERA_MUTEX_SECTION (NOBUG_ON, &n)
{
printf ("inner mutex locked section\n");
}
}
lumiera_mutex_destroy (&n, &NOBUG_FLAG(NOBUG_ON));
lumiera_mutex_destroy (&m, &NOBUG_FLAG(NOBUG_ON));
}
TEST ("rwlocksection")
{
lumiera_rwlock rwlock;
lumiera_rwlock_init (&rwlock, "rwsection", &NOBUG_FLAG(NOBUG_ON));
LUMIERA_WRLOCK_SECTION (NOBUG_ON, &rwlock)
{
printf ("write locked section 1\n");
}
LUMIERA_RDLOCK_SECTION (NOBUG_ON, &rwlock)
{
printf ("read locked section 2\n");
}
lumiera_rwlock_destroy (&rwlock, &NOBUG_FLAG(NOBUG_ON));
}
TEST ("rwlockforgotunlock")
{
lumiera_rwlock rwlock;
lumiera_rwlock_init (&rwlock, "rwlockforgotunlock", &NOBUG_FLAG(NOBUG_ON));
LUMIERA_RDLOCK_SECTION (NOBUG_ON, &rwlock)
{
break; // LOCK_SECTIONS must not be left by a jump
}
lumiera_rwlock_destroy (&rwlock, &NOBUG_FLAG(NOBUG_ON));
}
TEST ("conditionsection")
{
lumiera_condition cond;
lumiera_condition_init (&cond, "conditionsection", &NOBUG_FLAG(NOBUG_ON));
LUMIERA_CONDITION_SECTION (NOBUG_ON, &cond)
{
printf ("condition locked section 1\n");
}
LUMIERA_CONDITION_SECTION (NOBUG_ON, &cond)
{
printf ("condition locked section 2\n");
}
lumiera_condition_destroy (&cond, &NOBUG_FLAG(NOBUG_ON));
}
TEST ("conditionforgotunlock")
{
lumiera_condition cond;
lumiera_condition_init (&cond, "conditionforgotunlock", &NOBUG_FLAG(NOBUG_ON));
LUMIERA_CONDITION_SECTION (NOBUG_ON, &cond)
{
break; // CONDITION_SECTIONS must not be left by a jump
}
lumiera_condition_destroy (&cond, &NOBUG_FLAG(NOBUG_ON));
}
TESTS_END

View file

@ -1,8 +1,8 @@
/*
test-uuid.c - test the uuid lib
test-luid.c - test the luid lib
Copyright (C) CinelerraCV
2007, Christian Thaeter <ct@pipapo.org>
Copyright (C) Lumiera.org
2007, 2008 Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
@ -23,7 +23,7 @@
//#include <stdio.h>
#include "lib/uuid.h"
#include "lib/luid.h"
#include <nobug.h>
@ -39,35 +39,43 @@ main (int argc, char** argv)
if (!strcmp(argv[1], "uuidgen_2"))
{
lumiera_uuid uuid1;
lumiera_uuid uuid2;
lumiera_uid luid1;
lumiera_uid luid2;
lumiera_uuid_gen (&uuid1);
lumiera_uuid_gen (&uuid2);
lumiera_uid_gen (&luid1);
lumiera_uid_gen (&luid2);
printf ("%d\n", lumiera_uuid_eq (&uuid2, &uuid1));
printf ("%d\n", lumiera_uid_eq (&luid2, &luid1));
}
else if (!strcmp(argv[1], "uuidgen_copy"))
{
lumiera_uuid uuid1;
lumiera_uuid uuid2;
lumiera_uid luid1;
lumiera_uid luid2;
lumiera_uuid_gen (&uuid1);
lumiera_uid_gen (&luid1);
lumiera_uuid_copy (&uuid2, &uuid1);
lumiera_uid_copy (&luid2, &luid1);
printf ("%d\n", lumiera_uuid_eq (&uuid2, &uuid1));
printf ("%d\n", lumiera_uid_eq (&luid2, &luid1));
}
else if (!strcmp(argv[1], "ptrs"))
{
lumiera_uuid uuid;
lumiera_uid luid;
lumiera_uuid_set_ptr (&uuid, &uuid);
lumiera_uid_set_ptr (&luid, &luid);
printf ("%d\n", lumiera_uuid_ptr_get (&uuid) == &uuid);
printf ("%d\n", lumiera_uid_ptr_get (&luid) == &luid);
}
else
return 1;
return 0;
}
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

471
tests/library/test-psplay.c Normal file
View file

@ -0,0 +1,471 @@
/*
test-psplay.c - test the probanilistic splay tree
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <time.h>
#include <stdlib.h>
#include "lib/psplay.h"
#include "tests/test.h"
struct testitem
{
psplaynode node;
char* key;
};
typedef struct testitem* TestItem;
TestItem
testitem_new (const char* str)
{
TestItem self = malloc (sizeof *self);
psplaynode_init (&self->node);
self->key = strdup (str);
return self;
}
void
testitem_delete (TestItem self)
{
free (self->key);
free (self);
}
static int
cmp_fn (const void*, const void*);
static const void*
key_fn (const PSplaynode);
static void
delete_fn (PSplaynode);
//static psplay_delete_fn
//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data);
static int
fcmp_fn (const void*, const void*);
static const void*
fkey_fn (const PSplaynode);
static void
fdelete_fn (PSplaynode);
//static psplay_delete_fn
//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data);
psplay_delete_fn
testitem_print_node (PSplaynode node, const enum psplay_order_enum which, int level, void* data)
{
FILE* fh = data;
static char* sp = " ";
if (level>40)
{
if (which == PSPLAY_PREORDER)
fprintf (fh, "%s ...\n", sp);
return PSPLAY_CONT;
}
switch (which)
{
case PSPLAY_PREORDER:
fprintf (fh, "%s%p '%s'\n", sp+40-level, node, ((TestItem)node)->key);
if (node->left) fprintf (fh, "%sleft %p '%s'\n", sp+40-level, node->left, ((TestItem)node->left)->key);
break;
case PSPLAY_INORDER:
if (node->right) fprintf (fh, "%sright %p '%s'\n", sp+40-level, node->right, ((TestItem)node->right)->key);
break;
case PSPLAY_POSTORDER:
break;
}
return PSPLAY_CONT;
}
void
testitem_dump (PSplay self, FILE* dest)
{
fprintf (dest, "root %p '%s'\n", self->tree, self->tree?((TestItem)self->tree)->key:"EMPTY");
psplay_walk (self, NULL, testitem_print_node, 0, dest);
fprintf (dest, "\n");
}
psplay_delete_fn
testitem_graphvizprint_node (PSplaynode node, const enum psplay_order_enum which, int level, void* data)
{
FILE* fh = data;
switch (which)
{
case PSPLAY_PREORDER:
if (node->left)
fprintf (fh, "\t\"%p:%s\":sw -> \"%p:%s\":ne;\n",
node,
((TestItem)node)->key,
node->left,
((TestItem)node->left)->key);
break;
case PSPLAY_INORDER:
if (node->right)
fprintf (fh, "\t\"%p:%s\":se -> \"%p:%s\":nw;\n",
node,
((TestItem)node)->key,
node->right,
((TestItem)node->right)->key);
break;
case PSPLAY_POSTORDER:
break;
}
return PSPLAY_CONT;
}
void
testitem_graphvizdump (PSplay self, FILE* dest)
{
static int cnt = 0;
if (!cnt) cnt = (time(NULL) % 1000) * 100;
char cmd[256];
sprintf(cmd,"dot -Tps >/var/tmp/dbg%d.ps; gv /var/tmp/dbg%d.ps",cnt,cnt);
FILE * graph = popen(cmd, "w");
fprintf(graph, "digraph \"%s\" { center=true; size=\"6,6\"; node [color=lightblue2, style=filled];", "psplay");
++cnt;
fprintf(graph, "\t\"root\":s -> \"%p:%s\":n;\n",
self->tree, self->tree?((TestItem)self->tree)->key:"EMPTY");
psplay_walk (self, NULL, testitem_graphvizprint_node, 0, graph);
fprintf(graph, "}");
pclose(graph);
}
TESTS_BEGIN
TEST ("basic")
{
psplay splay_tree;
psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn);
psplay_dump (&splay_tree, stdout);
psplay_destroy (&splay_tree);
}
TEST ("basic_insert_dump")
{
REQUIRE (argv[2]);
psplay splay_tree;
psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn);
int end = atoi (argv[2]);
char key[1024];
for (int i = 1; i <= end; ++i)
{
sprintf (key, "%d", i);
TRACE (tests, "insert %s", key);
psplay_insert (&splay_tree, (PSplaynode)testitem_new (key), 100);
}
psplay_dump (&splay_tree, stderr);
#if 0
for (int i = 1; i <= end; ++i)
{
sprintf (key, "%d", i);
TRACE (tests, "insert %s", key);
psplay_remove_key (&splay_tree, key);
psplay_dump (&splay_tree, stderr);
}
for (int i = end; i; --i)
{
sprintf (key, "%d", i);
TRACE (tests, "insert %s", key);
psplay_remove_key (&splay_tree, key);
psplay_dump (&splay_tree, stderr);
}
#endif
psplay_destroy (&splay_tree);
printf ("done\n");
}
TEST ("insert_find")
{
psplay splay_tree;
psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn);
psplay_insert (&splay_tree, (PSplaynode)testitem_new ("foo"), 100);
psplay_insert (&splay_tree, (PSplaynode)testitem_new ("bar"), 100);
psplay_insert (&splay_tree, (PSplaynode)testitem_new ("baz"), 100);
psplay_insert (&splay_tree, (PSplaynode)testitem_new ("test"), 100);
psplay_insert (&splay_tree, (PSplaynode)testitem_new ("pap"), 100);
psplay_insert (&splay_tree, (PSplaynode)testitem_new ("qux"), 100);
testitem_graphvizdump (&splay_tree, stdout);
psplay_dump (&splay_tree, stdout);
//TestItem f = (TestItem) psplay_find (&splay_tree, "baz", 100);
TestItem f = (TestItem) psplay_find (&splay_tree, "baz", 100);
ENSURE (f);
printf ("found %p (%.4s)\n", &f->node, f->key);
psplay_dump (&splay_tree, stdout);
f = (TestItem) psplay_find (&splay_tree, "test", 100);
ENSURE (f);
printf ("found %p (%.4s)\n", &f->node, f->key);
psplay_dump (&splay_tree, stdout);
f = (TestItem) psplay_find (&splay_tree, "test", 100);
ENSURE (f);
printf ("found %p (%.4s)\n", &f->node, f->key);
psplay_dump (&splay_tree, stdout);
f = (TestItem) psplay_find (&splay_tree, "foo", 100);
ENSURE (f);
printf ("found %p (%.4s)\n", &f->node, f->key);
psplay_dump (&splay_tree, stdout);
#if 0
psplay_delete (psplay_remove (&splay_tree, root.tree));
psplay_dump (&splay_tree, stdout);
psplay_delete (psplay_remove (&splay_tree, root.tree));
psplay_dump (&splay_tree, stdout);
psplay_delete (psplay_remove (&splay_tree, root.tree));
psplay_dump (&splay_tree, stdout);
#endif
printf ("destroying\n");
psplay_destroy (&splay_tree);
psplay_dump (&splay_tree, stdout);
#if 0
psplay_delete (psplay_remove (&splay_tree, root.tree));
psplay_dump (&splay_tree, stdout);
psplay_delete (psplay_remove (&splay_tree, root.tree));
psplay_dump (&splay_tree, stdout);
psplay_delete (psplay_remove (&splay_tree, root.tree));
psplay_dump (&splay_tree, stdout);
#endif
return 0;
}
TEST ("basic_insert_splay")
{
REQUIRE (argv[2]);
psplay splay_tree;
psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn);
int end = atoi (argv[2]);
char key[1024];
for (int i = 1; i <= end; ++i)
{
sprintf (key, "%d", i);
TRACE (tests, "insert %s", key);
psplay_insert (&splay_tree, (PSplaynode)testitem_new (key), 100);
}
for (int i = end/2; i <= end; ++i)
{
psplay_dump (&splay_tree, stderr);
sprintf (key, "%d", i);
psplay_find (&splay_tree, key, 100);
}
psplay_destroy (&splay_tree);
printf ("done\n");
}
TEST ("basic_rand_insert_dump")
{
REQUIRE (argv[2]);
psplay splay_tree;
psplay_init (&splay_tree, cmp_fn, key_fn, delete_fn);
int end = atoi (argv[2]);
char key[1024];
for (int i = 1; i <= end; ++i)
{
sprintf (key, "%d", i /*rand()*/);
psplay_insert (&splay_tree, (PSplaynode)testitem_new (key), 100);
}
testitem_graphvizdump (&splay_tree, stdout);
//testitem_dump (&splay_tree, stdout);
psplay_destroy (&splay_tree);
printf ("done\n");
}
TEST ("fast_insert")
{
REQUIRE (argv[2]);
psplay splay_tree;
psplay_init (&splay_tree, fcmp_fn, fkey_fn, fdelete_fn);
int end = atoi (argv[2]);
char key[1024];
for (int i = 1; i <= end; ++i)
{
sprintf (key, "%d", i);
psplay_insert (&splay_tree, (PSplaynode)testitem_new (key), 100);
}
psplay_destroy (&splay_tree);
printf ("done\n");
}
TEST ("nonexistant")
{
REQUIRE (argv[2]);
}
TEST ("insert")
{
REQUIRE (argv[2]);
}
TEST ("insert_rand")
{
REQUIRE (argv[2]);
}
TEST ("insert_fastcheck")
{
REQUIRE (argv[2]);
}
TESTS_END
/*
cuckoo support functions
*/
static int
cmp_fn (const void* a, const void* b)
{
REQUIRE (a);
REQUIRE (b);
return strcmp (a, b);
}
static const void*
key_fn (const PSplaynode node)
{
REQUIRE (node);
REQUIRE (((TestItem)node)->key);
return ((TestItem)node)->key;
}
static void
delete_fn (PSplaynode node)
{
REQUIRE (node);
testitem_delete ((TestItem) node);
}
//static psplay_delete_fn
//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data)
//{
//}
static int
fcmp_fn (const void* a, const void* b)
{
return strcmp (a, b);
}
static const void*
fkey_fn (const PSplaynode node)
{
return ((TestItem)node)->key;
}
static void
fdelete_fn (PSplaynode node)
{
testitem_delete ((TestItem) node);
}
//static psplay_delete_fn
//action_fn (PSplaynode node, const enum psplay_order_e which, int level, void* data)
//{
//}
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/

View file

@ -1,77 +0,0 @@
/*
test-references.c - test strong and weak references
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <stdio.h>
//#include <string.h>
#include "lib/references.h"
LUMIERA_ERROR_DEFINE(TEST, "test error");
struct example
{
int foo;
};
void
example_dtor(void* o)
{
printf ("destruct: %d\n", ((struct example*)o)->foo);
((struct example*)o)->foo = 0;
// free(o)
}
int
main (int argc, char** argv)
{
NOBUG_INIT;
if (argc == 1)
return 0;
if (!strcmp(argv[1], "basic"))
{
struct example test;
test.foo = 123;
lumiera_reference hold;
lumiera_reference_strong_init_once (&hold, &test, example_dtor);
struct example* r = lumiera_reference_get (&hold);
printf ("got: %d\n", r->foo);
lumiera_reference_destroy (&hold);
}
else if (!strcmp(argv[1], "nodeinsert"))
{
}
else
return 1;
return 0;
}

View file

@ -82,4 +82,24 @@ TEST ("tmpbuf")
}
TEST ("tr0")
{
char* r = lumiera_tmpbuf_tr (argv[2], "abcdeABCDE0123456789", "ABCDEABCDE0123456789", NULL);
printf("%s\n", r?r:"failed");
}
TEST ("tr")
{
char* r = lumiera_tmpbuf_tr (argv[2], "abcdeABCDE0123456789", "ABCDEABCDE0123456789", "");
printf("%s\n", r?r:"failed");
}
TEST ("tr_")
{
printf("%s\n", lumiera_tmpbuf_tr (argv[2], "abcdeABCDE0123456789", "ABCDEABCDE0123456789", "_"));
}
TESTS_END

View file

@ -1,49 +0,0 @@
/*
test condition functions
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "lib/condition.h"
#if 0
waiting_thread()
{
lock;
wait;
unlock;
}
signaling_thread()
{
signal();
}
#endif
int
conditionforgotunlock ()
{
lumiera_condition c;
lumiera_condition_init (&c);
lumiera_conditionacquirer l;
lumiera_conditionacquirer_init (&l, &c, LUMIERA_LOCKED);
return 0;
}

View file

@ -1,32 +0,0 @@
/*
test mutex functions
Copyright (C) Lumiera.org
2008, Christian Thaeter <ct@pipapo.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "lib/mutex.h"
int mutexforgotunlock()
{
lumiera_mutex m;
lumiera_mutex_init (&m);
lumiera_mutexacquirer l;
lumiera_mutexacquirer_init_mutex (&l, &m, LUMIERA_LOCKED);
return 0;
}

View file

@ -26,6 +26,9 @@
#include "lib/error.h"
#include <stdio.h>
NOBUG_DEFINE_FLAG (tests);
LUMIERA_ERROR_DEFINE (TEST, "test error");
#define TESTS_BEGIN \
@ -33,20 +36,35 @@ int \
main (int argc, char** argv) \
{ \
NOBUG_INIT; \
NOBUG_INIT_FLAG (tests); \
\
if (argc == 1) \
return 1;
{ \
fprintf (stderr, "missing argument\n"); \
return 1; \
}
#define TEST(name) \
#define TEST(name) \
else if (!strcmp(argv[1], name))
#define TESTS_END \
else \
return 1; \
{ \
fprintf (stderr, "unknown test\n"); \
return 1; \
} \
\
return 0; \
}
#endif
/*
// Local Variables:
// mode: C
// c-file-style: "gnu"
// indent-tabs-mode: nil
// End:
*/