aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore10
-rw-r--r--INSTALL56
-rw-r--r--Makefile286
-rw-r--r--README17
-rw-r--r--SConstruct232
-rw-r--r--arch/arm/include/asm/cycles.h23
-rw-r--r--arch/sparc/include/asm/cycles.h16
-rw-r--r--arch/x86/include/asm/cycles.h30
-rw-r--r--arch/x86/include/asm/irq.h15
-rw-r--r--bin/cycles.c2
-rw-r--r--bin/null_call.c3
-rw-r--r--bin/rtspin.c261
-rw-r--r--inc/depend.makefile22
-rw-r--r--include/asm.h15
-rw-r--r--include/asm_sparc.h92
-rw-r--r--include/asm_x86.h144
-rw-r--r--include/cycles.h63
-rw-r--r--include/litmus.h24
-rwxr-xr-xsetsched11
-rwxr-xr-xshowsched2
-rw-r--r--src/clocks.c23
-rw-r--r--src/kernel_iface.c3
-rw-r--r--src/litmus.c2
-rw-r--r--src/syscalls.c29
-rw-r--r--tests/core_api.c42
-rw-r--r--tests/fdso.c39
-rw-r--r--tests/locks.c110
-rwxr-xr-xtests/make_catalog.py5
-rw-r--r--tests/runner.c4
29 files changed, 845 insertions, 736 deletions
diff --git a/.gitignore b/.gitignore
index f420aa3..7f419d0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,8 +2,11 @@
2*.o 2*.o
3*.a 3*.a
4 4
5
6
5# generated files 7# generated files
6tests/__test_catalog.inc 8tests/test_catalog.inc
9*.d
7 10
8# executables 11# executables
9runtests 12runtests
@@ -20,8 +23,5 @@ rtspin
20cycles 23cycles
21measure_syscall 24measure_syscall
22 25
23# scons files 26# build system files
24.sconsign.dblite
25.sconf_temp/*
26config.log
27.config 27.config
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..4891f0a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,56 @@
1
2Liblitmus Installation Instructions
3===================================
4
5Dependencies
6------------
7
8Liblitmus has no dependencies besides the kernel. During compilation, the
9Makefile will attempt to copy required headers from the kernel source tree into
10the library source tree.
11
12
13Configuration
14-------------
15
16The build system reads a local configuration file named '.config' (just like the
17kernel, but much simpler). There are three variables that affect the
18compilation process:
19
20 LITMUS_KERNEL --- Path (relative or absolute) to the LITMUS^RT kernel
21 source tree. The default value is
22 '../litmus2010'. Set this variable if you extracted
23 the kernel somewhere else.
24
25 ARCH --- The target architecture. Currently, liblitmus can be
26 build for i386, x86_64, sparc64, and arm. The default
27 value is the host architecture.
28
29 CROSS_COMPILE --- A prefix for the compiler and linker to use. Works
30 exactly like cross-compiling the kernel. By default,
31 this variable is not set.
32
33Makefile Targets
34----------------
35
36 all --- Build the library, all tools, and all tests. This is
37 the default.
38
39 lib --- Build only the library.
40
41 help --- Display this help.
42
43 dump-config --- Report the build configuration. Use this to debug
44 build problems.
45
46 clean --- Remove all build files and binaries.
47
48 TAGS --- Create a TAGS file for emacs. (Requires etags to be
49 installed.)
50
51 tags --- Create a tags file for vim. (Requires ctags to be
52 installed.)
53
54 cscope --- Create a symbol database for cscope. (Requires cscope
55 to be installed.)
56
diff --git a/Makefile b/Makefile
index bb8fffa..db94ffb 100644
--- a/Makefile
+++ b/Makefile
@@ -1,17 +1,279 @@
1.PHONY: all-32 all-64 all-sparc clean purge 1# figure out what kind of host we are running on
2host-arch := $(shell uname -m | \
3 sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/)
2 4
3all-32: 5# ##############################################################################
4 echo "Legacy warning: Building is done with scons." 6# User variables
5 ARCH=x86 scons
6all-64:
7 ARCH=x86_64 scons
8 7
9all-sparc: 8# user variables can be specified in the environment or in a .config file
10 ARCH=sparc64 scons 9-include .config
10
11# ARCH -- what architecture are we compiling for?
12ARCH ?= ${host-arch}
13
14# LITMUS_KERNEL -- where to find the litmus kernel?
15LITMUS_KERNEL ?= ../litmus2010
16
17
18# ##############################################################################
19# Internal configuration.
20
21# compiler flags
22flags-debug = -Wall -Werror -g -Wdeclaration-after-statement
23flags-api = -D_XOPEN_SOURCE=600 -D_GNU_SOURCE
24
25# architecture-specific flags
26flags-i386 = -m32
27flags-x86_64 = -m64
28flags-sparc64 = -mcpu=v9 -m64
29# default: none
30
31# name of the directory that has the arch headers in the Linux source
32include-i386 = x86
33include-x86_64 = x86
34include-sparc64 = sparc
35# default: the arch name
36include-${ARCH} ?= ${ARCH}
37
38# name of the file(s) that holds the actual system call numbers
39unistd-i386 = unistd.h unistd_32.h
40unistd-x86_64 = unistd.h unistd_64.h
41# default: unistd.h
42unistd-${ARCH} ?= unistd.h
43
44# by default we use the local version
45LIBLITMUS ?= .
46
47# where to find header files
48headers = -I${LIBLITMUS}/include -I${LIBLITMUS}/arch/${include-${ARCH}}/include
49
50# combine options
51CPPFLAGS = ${flags-api} ${flags-${ARCH}} -DARCH=${ARCH} ${headers}
52CFLAGS = ${flags-debug}
53LDFLAGS = ${flags-${ARCH}}
54
55# how to link against liblitmus
56liblitmus-flags = -L${LIBLITMUS} -llitmus
57
58# Force gcc instead of cc, but let the user specify a more specific version if
59# desired.
60ifeq (${CC},cc)
61CC = gcc
62endif
63
64# incorporate cross-compiler (if any)
65CC := ${CROSS_COMPILE}${CC}
66LD := ${CROSS_COMPILE}${LD}
67AR := ${CROSS_COMPILE}${AR}
68
69# ##############################################################################
70# Targets
71
72all = lib ${rt-apps}
73rt-apps = cycles base_task rt_launch rtspin release_ts measure_syscall \
74 base_mt_task runtests
75
76.PHONY: all lib clean dump-config TAGS tags cscope help
77
78all: ${all} inc/config.makefile
79
80# Write a distilled version of the flags for clients of the library. Ideally,
81# this should depend on liblitmus.a, but that requires LIBLITMUS to be a
82# private override. Private overrides are only supported starting with make
83# 3.82, which is not yet in common use.
84inc/config.makefile: LIBLITMUS = $${LIBLITMUS}
85inc/config.makefile: Makefile
86 @printf "%-15s= %-20s\n" \
87 ARCH ${ARCH} \
88 CFLAGS '${CFLAGS}' \
89 LDFLAGS '${LDFLAGS}' \
90 LDLIBS '${liblitmus-flags}' \
91 CPPFLAGS '${CPPFLAGS}' \
92 CC '${shell which ${CC}}' \
93 LD '${shell which ${LD}}' \
94 AR '${shell which ${AR}}' \
95 > $@
96
97dump-config:
98 @echo Build configuration:
99 @printf "%-15s= %-20s\n" \
100 ARCH ${ARCH} \
101 LITMUS_KERNEL "${LITMUS_KERNEL}" \
102 CROSS_COMPILE "${CROSS_COMPILE}" \
103 headers "${headers}" \
104 "kernel headers" "${imported-headers}" \
105 CFLAGS "${CFLAGS}" \
106 LDFLAGS "${LDFLAGS}" \
107 CPPFLAGS "${CPPFLAGS}" \
108 CC "${CC}" \
109 CPP "${CPP}" \
110 LD "${LD}" \
111 AR "${AR}" \
112 obj-all "${obj-all}"
113
114help:
115 @cat INSTALL
11 116
12clean: 117clean:
13 echo "Legacy warning: Building is now done with scons." 118 rm -f ${rt-apps}
14 scons -c 119 rm -f *.o *.d *.a test_catalog.inc
120 rm -f ${imported-headers}
121 rm -f inc/config.makefile
122 rm -f tags TAGS cscope.files cscope.out
123
124# Emacs Tags
125TAGS:
126 @echo TAGS
127 @find . -type f -and -iname '*.[ch]' | xargs etags
128
129# Vim Tags
130tags:
131 @echo tags
132 @find . -type f -and -iname '*.[ch]' | xargs ctags
133
134# cscope DB
135cscope:
136 @echo cscope
137 @find . -type f -and -iname '*.[ch]' | xargs printf "%s\n" > cscope.files
138 @cscope -b
139
140# ##############################################################################
141# Kernel headers.
142# The kernel does not like being #included directly, so let's
143# copy out the parts that we need.
144
145# Litmus headers
146include/litmus/%.h: ${LITMUS_KERNEL}/include/litmus/%.h
147 @mkdir -p ${dir $@}
148 cp $< $@
149
150# asm headers
151arch/${include-${ARCH}}/include/asm/%.h: \
152 ${LITMUS_KERNEL}/arch/${include-${ARCH}}/include/asm/%.h
153 @mkdir -p ${dir $@}
154 cp $< $@
155
156litmus-headers = include/litmus/rt_param.h include/litmus/unistd_32.h \
157 include/litmus/unistd_64.h
158
159unistd-headers = \
160 $(foreach file,${unistd-${ARCH}},arch/${include-${ARCH}}/include/asm/$(file))
161
162
163imported-headers = ${litmus-headers} ${unistd-headers}
164
165# Let's not copy these twice.
166.SECONDARY: ${imported-headers}
167
168# ##############################################################################
169# liblitmus
170
171lib: liblitmus.a
172
173# all .c file in src/ are linked into liblitmus
174vpath %.c src/
175obj-lib = $(patsubst src/%.c,%.o,$(wildcard src/*.c))
176
177liblitmus.a: ${obj-lib}
178 ${AR} rcs $@ $+
179
180# ##############################################################################
181# Tests suite.
182
183# tests are found in tests/
184vpath %.c tests/
185
186src-runtests = $(wildcard tests/*.c)
187obj-runtests = $(patsubst tests/%.c,%.o,${src-runtests})
188
189# generate list of tests automatically
190test_catalog.inc: $(filter-out tests/runner.c,${src-runtests})
191 tests/make_catalog.py $+ > $@
192
193tests/runner.c: test_catalog.inc
194
195
196# ##############################################################################
197# Tools that link with liblitmus
198
199# these source files are found in bin/
200vpath %.c bin/
201
202obj-cycles = cycles.o
203
204obj-base_task = base_task.o
205
206obj-base_mt_task = base_mt_task.o
207ldf-base_mt_task = -pthread
208
209obj-rt_launch = rt_launch.o common.o
210
211obj-rtspin = rtspin.o common.o
212lib-rtspin = -lrt
213
214obj-release_ts = release_ts.o
215
216obj-measure_syscall = null_call.o
217lib-measure_syscall = -lm
218
219# ##############################################################################
220# Build everything that depends on liblitmus.
221
222.SECONDEXPANSION:
223${rt-apps}: $${obj-$$@} liblitmus.a
224 $(CC) -o $@ $(LDFLAGS) ${ldf-$@} $(filter-out liblitmus.a,$+) $(LOADLIBS) $(LDLIBS) ${lib-$@} ${liblitmus-flags}
225
226# ##############################################################################
227# Dependency resolution.
228
229vpath %.c bin/ src/ tests/
230
231obj-all = ${sort ${foreach target,${all},${obj-${target}}}}
232
233# rule to generate dependency files
234%.d: %.c ${imported-headers}
235 @set -e; rm -f $@; \
236 $(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
237 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
238 rm -f $@.$$$$
239
240ifeq ($(MAKECMDGOALS),)
241MAKECMDGOALS += all
242endif
243
244ifneq ($(filter-out dump-config clean help,$(MAKECMDGOALS)),)
245
246# Pull in dependencies.
247-include ${obj-all:.o=.d}
248
249# Let's make sure the kernel header path is ok.
250config-ok := $(shell test -d "${LITMUS_KERNEL}" || echo invalid path. )
251config-ok += $(shell test -f "${LITMUS_KERNEL}/${word 1,${litmus-headers}}" \
252 || echo cannot find header. )
253ifneq ($(strip $(config-ok)),)
254$(info (!!) Could not find a LITMUS^RT kernel at ${LITMUS_KERNEL}: ${config-ok})
255$(info (!!) Are you sure the path is correct?)
256$(info (!!) Run 'make dump-config' to see the build configuration.)
257$(info (!!) Edit the file .config to override the default configuration.)
258$(error Cannot build without access to the LITMUS^RT kernel source)
259endif
260
261kernel-unistd-hdrs := $(foreach file,${unistd-headers},${LITMUS_KERNEL}/$(file))
262hdr-ok := $(shell egrep '\#include ["<]litmus/unistd' ${kernel-unistd-hdrs} )
263ifeq ($(strip $(hdr-ok)),)
264$(info (!!) Could not find LITMUS^RT system calls in ${kernel-unistd-hdrs}.)
265$(error Your kernel headers do not seem to be LITMUS^RT headers)
266endif
267
268config-ok := $(shell test -f "${LITMUS_KERNEL}/${word 1,${unistd-headers}}" \
269 || echo fail )
270ifneq ($(config-ok),)
271$(info (!!) Could not find the architecture-specifc Linux headers.)
272$(info (!!) Are you sure ARCH=${ARCH} is correct?)
273$(info (!!) Run 'make dump-config' to see the build configuration.)
274$(info (!!) Edit the file '.config' to override the default configuration.)
275$(error Cannot build without access to the architecture-specific files)
276endif
277
278endif
15 279
16purge: clean
17 rm -rf .sconf_temp .sconsign.dblite
diff --git a/README b/README
index 656dc14..accdf72 100644
--- a/README
+++ b/README
@@ -54,18 +54,5 @@ Tools and Programs
54 of single-threaded real-time tasks. 54 of single-threaded real-time tasks.
55 55
56* base_mt_task 56* base_mt_task
57 Example multi-threaded real-time task. Use as a basis for development. 57 Example multi-threaded real-time task. Use as a basis for the development of
58 58 multithreaded real-time tasks.
59
60Install
61=======
62The library and the included tools must be compiled from source.
63Liblitmus uses SCons as the build system. For details see:
64
65 http://www.scons.org/
66
67To compile the library just execute the command 'scons' without
68arguments.
69
70x86_64->ia32 cross compilation is possible by specifying ARCH=i386 on the
71command line or in the environment.
diff --git a/SConstruct b/SConstruct
deleted file mode 100644
index c41e41e..0000000
--- a/SConstruct
+++ /dev/null
@@ -1,232 +0,0 @@
1Help("""
2=============================================
3liblitmus --- The LITMUS^RT Userspace Library
4
5There are a number of user-configurable build
6variables. These can either be set on the
7command line (e.g., scons ARCH=x86) or read
8from a local configuration file (.config).
9
10Run 'scons --dump-config' to see the final
11build configuration.
12
13""")
14
15import os
16(ostype, _, _, _, arch) = os.uname()
17
18# sanity check
19if ostype != 'Linux':
20 print 'Error: Building liblitmus is only supported on Linux.'
21 Exit(1)
22
23
24# #####################################################################
25# Internal configuration.
26DEBUG_FLAGS = '-Wall -g -Wdeclaration-after-statement'
27API_FLAGS = '-D_XOPEN_SOURCE=600 -D_GNU_SOURCE'
28X86_32_FLAGS = '-m32'
29X86_64_FLAGS = '-m64'
30V9_FLAGS = '-mcpu=v9 -m64'
31
32SUPPORTED_ARCHS = {
33 'sparc64' : V9_FLAGS,
34 'x86' : X86_32_FLAGS,
35 'x86_64' : X86_64_FLAGS,
36}
37
38ARCH_ALIAS = {
39 'i686' : 'x86'
40}
41
42# name of the directory that has the arch headers in the Linux source
43INCLUDE_ARCH = {
44 'sparc64' : 'sparc',
45 'x86' : 'x86',
46 'x86_64' : 'x86',
47}
48
49INCLUDE_DIRS = [
50 # library headers
51 'include/',
52 # Linux kernel headers
53 '${LITMUS_KERNEL}/include/',
54 # Linux architecture-specific kernel headers
55 '$LITMUS_KERNEL/arch/${INCLUDE_ARCH}/include'
56 ]
57
58# #####################################################################
59# User configuration.
60
61vars = Variables('.config', ARGUMENTS)
62
63vars.AddVariables(
64 PathVariable('LITMUS_KERNEL',
65 'Where to find the LITMUS^RT kernel.',
66 '../litmus2010'),
67
68 EnumVariable('ARCH',
69 'Target architecture.',
70 arch,
71 SUPPORTED_ARCHS.keys() + ARCH_ALIAS.keys()),
72)
73
74AddOption('--dump-config',
75 dest='dump',
76 action='store_true',
77 default=False,
78 help="dump the build configuration and exit")
79
80# #####################################################################
81# Build configuration.
82
83env = Environment(variables = vars)
84
85# Check what we are building for.
86arch = env['ARCH']
87
88# replace if the arch has an alternative name
89if arch in ARCH_ALIAS:
90 arch = ARCH_ALIAS[arch]
91 env['ARCH'] = arch
92
93# Get include directory for arch.
94env['INCLUDE_ARCH'] = INCLUDE_ARCH[arch]
95
96arch_flags = Split(SUPPORTED_ARCHS[arch])
97dbg_flags = Split(DEBUG_FLAGS)
98api_flags = Split(API_FLAGS)
99
100# Set up environment
101env.Replace(
102 CC = 'gcc',
103 CPPPATH = INCLUDE_DIRS,
104 CCFLAGS = dbg_flags + api_flags + arch_flags,
105 LINKFLAGS = arch_flags,
106)
107
108def dump_config(env):
109 def dump(key):
110 print "%15s = %s" % (key, env.subst("${%s}" % key))
111
112 dump('ARCH')
113 dump('LITMUS_KERNEL')
114 dump('CPPPATH')
115 dump('CCFLAGS')
116 dump('LINKFLAGS')
117
118if GetOption('dump'):
119 print "\n"
120 print "Build Configuration:"
121 dump_config(env)
122 print "\n"
123 Exit(0)
124
125# #####################################################################
126# Build checks.
127
128def CheckSyscallNr(context):
129 context.Message('Checking for LITMUS^RT syscall numbers... ')
130 nrSrc = """
131#include <linux/unistd.h>
132int main(int argc, char **argv)
133{
134 return __NR_set_rt_task_param;
135}
136"""
137 result = context.TryLink(nrSrc, '.c')
138 context.Result(result)
139 return result
140
141
142def abort(msg, help=None):
143 print "Error: %s" % env.subst(msg)
144 print "-" * 80
145 print "This is the build configuration in use:"
146 dump_config(env)
147 if help:
148 print "-" * 80
149 print env.subst(help)
150 print "\n"
151 Exit(1)
152
153# Check compile environment
154if not (env.GetOption('clean') or env.GetOption('help')):
155 print env.subst('Building ${ARCH} binaries.')
156 # Check for kernel headers.
157 conf = Configure(env, custom_tests = {'CheckSyscallNr' : CheckSyscallNr})
158
159 conf.CheckCHeader('linux/unistd.h') or \
160 abort("Cannot find kernel headers in '$LITMUS_KERNEL'",
161 "Please ensure that LITMUS_KERNEL in .config is set to a valid path.")
162
163 conf.CheckCHeader('litmus/rt_param.h') or \
164 abort("Cannot find LITMUS^RT headers in '$LITMUS_KERNEL'",
165 "Please ensure sure that the kernel in '$LITMUS_KERNEL'"
166 " is a LITMUS^RT kernel.")
167
168 conf.CheckSyscallNr() or \
169 abort("The LITMUS^RT syscall numbers are not available.",
170 "Please ensure sure that the kernel in '$LITMUS_KERNEL'"
171 " is a LITMUS^RT kernel.")
172
173 env = conf.Finish()
174
175# #####################################################################
176# Derived environments
177
178# link with liblitmus
179rt = env.Clone(
180 LIBS = Split('litmus rt'),
181 LIBPATH = '.'
182)
183rt.Append(LINKFLAGS = '-static')
184
185
186# link with math lib
187rtm = rt.Clone()
188rtm.Append(LIBS = ['m'])
189
190# multithreaded real-time tasks
191mtrt = rt.Clone()
192mtrt.Append(LINKFLAGS = '-pthread')
193
194# #####################################################################
195# Targets: liblitmus
196# All the files in src/ are part of the library.
197env.Library('litmus',
198 ['src/kernel_iface.c', 'src/litmus.c',
199 'src/syscalls.c', 'src/task.c'])
200
201# #####################################################################
202# Targets: simple tools that do not depend on liblitmus
203env.Program('cycles', 'bin/cycles.c')
204
205# #####################################################################
206# Targets: tools that depend on liblitmus
207rt.Program('base_task', 'bin/base_task.c')
208mtrt.Program('base_mt_task', 'bin/base_mt_task.c')
209rt.Program('rt_launch', ['bin/rt_launch.c', 'bin/common.c'])
210rt.Program('rtspin', ['bin/rtspin.c', 'bin/common.c'])
211rt.Program('release_ts', 'bin/release_ts.c')
212rtm.Program('measure_syscall', 'bin/null_call.c')
213
214
215# #####################################################################
216# Test suite.
217
218mkc = Builder(action = 'tests/make_catalog.py $SOURCES > $TARGET')
219test = mtrt.Clone()
220test.Append(BUILDERS = {'TestCatalog' : mkc})
221test.Append(CPPPATH = ['tests/'])
222
223catalog = test.TestCatalog('tests/__test_catalog.inc', Glob('tests/*.c'))
224test.Program('runtests', Glob('tests/*.c'))
225
226# #####################################################################
227# Additional Help
228
229Help("Build Variables\n")
230Help("---------------\n")
231Help(vars.GenerateHelpText(env))
232
diff --git a/arch/arm/include/asm/cycles.h b/arch/arm/include/asm/cycles.h
new file mode 100644
index 0000000..73632f8
--- /dev/null
+++ b/arch/arm/include/asm/cycles.h
@@ -0,0 +1,23 @@
1#ifndef ASM_CYCLES_H
2#define ASM_CYCLES_H
3
4typedef unsigned long cycles_t;
5
6#define CYCLES_FMT "lu"
7
8/* system call wrapper */
9int null_call(cycles_t *timestamp);
10
11static inline cycles_t get_cycles(void)
12{
13 cycles_t c;
14 /* On the ARM11 MPCore chips, userspace cannot access the cycle counter
15 * directly. So ask the kernel to read it instead. Eventually, this
16 * should support newer ARM chips that do allow accessing the cycle
17 * counter in userspace.
18 */
19 null_call(&c);
20 return c;
21}
22
23#endif
diff --git a/arch/sparc/include/asm/cycles.h b/arch/sparc/include/asm/cycles.h
new file mode 100644
index 0000000..ce0e8ce
--- /dev/null
+++ b/arch/sparc/include/asm/cycles.h
@@ -0,0 +1,16 @@
1#ifndef ASM_CYCLES_H
2#define ASM_CYCLES_H
3
4#define NPT_BIT 63
5
6typedef unsigned long cycles_t;
7
8#define CYCLES_FMT "lu"
9
10static inline cycles_t get_cycles(void) {
11 cycles_t cycles = 0;
12 __asm__ __volatile__("rd %%asr24, %0" : "=r" (cycles));
13 return cycles & ~(1UL << NPT_BIT);
14}
15
16#endif
diff --git a/arch/x86/include/asm/cycles.h b/arch/x86/include/asm/cycles.h
new file mode 100644
index 0000000..00a7593
--- /dev/null
+++ b/arch/x86/include/asm/cycles.h
@@ -0,0 +1,30 @@
1#ifndef ASM_CYCLES_H
2#define ASM_CYCLES_H
3
4#define rdtscll(val) do { \
5 unsigned int __a,__d; \
6 __asm__ __volatile__("rdtsc" : "=a" (__a), "=d" (__d)); \
7 (val) = ((unsigned long long)__a) | (((unsigned long long)__d)<<32); \
8} while(0)
9
10static __inline__ unsigned long long native_read_tsc(void)
11{
12 unsigned long long val;
13
14 __asm__ __volatile__("mfence":::"memory");
15 rdtscll(val);
16 __asm__ __volatile__("mfence":::"memory");
17
18 return val;
19}
20
21#define CYCLES_FMT "llu"
22
23typedef unsigned long long cycles_t;
24
25static inline cycles_t get_cycles(void)
26{
27 return native_read_tsc();
28}
29
30#endif
diff --git a/arch/x86/include/asm/irq.h b/arch/x86/include/asm/irq.h
new file mode 100644
index 0000000..23f47fd
--- /dev/null
+++ b/arch/x86/include/asm/irq.h
@@ -0,0 +1,15 @@
1#ifndef ASM_IRQ_H
2#define ASM_IRQ_H
3
4/* please, use these only if you _really_ know what you're doing
5 * ... and remember iopl(3) first!! (include sys/io.h)
6 */
7static inline void cli(void) {
8 asm volatile("cli": : :"memory");
9}
10
11static inline void sti(void) {
12 asm volatile("sti": : :"memory");
13}
14
15#endif
diff --git a/bin/cycles.c b/bin/cycles.c
index a6b9308..babd073 100644
--- a/bin/cycles.c
+++ b/bin/cycles.c
@@ -2,7 +2,7 @@
2#include <stdlib.h> 2#include <stdlib.h>
3#include <unistd.h> 3#include <unistd.h>
4 4
5#include "cycles.h" 5#include "asm/cycles.h"
6 6
7int main(int argc, char** argv) 7int main(int argc, char** argv)
8{ 8{
diff --git a/bin/null_call.c b/bin/null_call.c
index 94ba866..d714e77 100644
--- a/bin/null_call.c
+++ b/bin/null_call.c
@@ -5,7 +5,6 @@
5#include <math.h> 5#include <math.h>
6 6
7#include "litmus.h" 7#include "litmus.h"
8#include "cycles.h"
9 8
10static void time_null_call(void) 9static void time_null_call(void)
11{ 10{
@@ -49,6 +48,8 @@ int main(int argc, char **argv)
49 "%lus and %luns.\n", 48 "%lus and %luns.\n",
50 (unsigned long) sleep_time.tv_sec, 49 (unsigned long) sleep_time.tv_sec,
51 (unsigned long) sleep_time.tv_nsec); 50 (unsigned long) sleep_time.tv_nsec);
51 fprintf(stderr, "%10s, %10s, %10s, %10s, %10s, %10s\n",
52 "pre", "in kernel", "post", "entry", "exit", "total");
52 do { 53 do {
53 time_null_call(); 54 time_null_call();
54 } while (nanosleep(&sleep_time, NULL) == 0); 55 } while (nanosleep(&sleep_time, NULL) == 0);
diff --git a/bin/rtspin.c b/bin/rtspin.c
index 20ce734..28c4a4e 100644
--- a/bin/rtspin.c
+++ b/bin/rtspin.c
@@ -4,40 +4,98 @@
4#include <stdlib.h> 4#include <stdlib.h>
5#include <unistd.h> 5#include <unistd.h>
6#include <time.h> 6#include <time.h>
7#include <assert.h>
7 8
8 9
9#include "litmus.h" 10#include "litmus.h"
10#include "common.h" 11#include "common.h"
11 12
12 13
13static double cputime() 14
15static void usage(char *error) {
16 fprintf(stderr, "Error: %s\n", error);
17 fprintf(stderr,
18 "Usage:\n"
19 " rt_spin [COMMON-OPTS] WCET PERIOD DURATION\n"
20 " rt_spin [COMMON-OPTS] -f FILE [-o COLUMN] WCET PERIOD\n"
21 " rt_spin -l\n"
22 "\n"
23 "COMMON-OPTS = [-w] [-p PARTITION] [-c CLASS] [-s SCALE]\n"
24 "\n"
25 "WCET and PERIOD are milliseconds, DURATION is seconds.\n");
26 exit(EXIT_FAILURE);
27}
28
29/*
30 * returns the character that made processing stop, newline or EOF
31 */
32static int skip_to_next_line(FILE *fstream)
14{ 33{
15 struct timespec ts; 34 int ch;
16 int err; 35 for (ch = fgetc(fstream); ch != EOF && ch != '\n'; ch = fgetc(fstream));
17 err = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts); 36 return ch;
18 if (err != 0)
19 perror("clock_gettime");
20 return (ts.tv_sec + 1E-9 * ts.tv_nsec);
21} 37}
22 38
23static double wctime() 39static void skip_comments(FILE *fstream)
24{ 40{
25 struct timeval tv; 41 int ch;
26 gettimeofday(&tv, NULL); 42 for (ch = fgetc(fstream); ch == '#'; ch = fgetc(fstream))
27 return (tv.tv_sec + 1E-6 * tv.tv_usec); 43 skip_to_next_line(fstream);
44 ungetc(ch, fstream);
28} 45}
29 46
30void usage(char *error) { 47static void get_exec_times(const char *file, const int column,
31 fprintf(stderr, "Error: %s\n", error); 48 int *num_jobs, double **exec_times)
32 fprintf(stderr, 49{
33 "Usage: rt_spin [-w] [-p PARTITION] [-c CLASS] WCET PERIOD DURATION\n" 50 FILE *fstream;
34 " rt_spin -l\n"); 51 int cur_job, cur_col, ch;
35 exit(1); 52 *num_jobs = 0;
53
54 fstream = fopen(file, "r");
55 if (!fstream)
56 bail_out("could not open execution time file");
57
58 /* figure out the number of jobs */
59 do {
60 skip_comments(fstream);
61 ch = skip_to_next_line(fstream);
62 if (ch != EOF)
63 ++(*num_jobs);
64 } while (ch != EOF);
65
66 if (-1 == fseek(fstream, 0L, SEEK_SET))
67 bail_out("rewinding file failed");
68
69 /* allocate space for exec times */
70 *exec_times = calloc(*num_jobs, sizeof(*exec_times));
71 if (!*exec_times)
72 bail_out("couldn't allocate memory");
73
74 for (cur_job = 0; cur_job < *num_jobs && !feof(fstream); ++cur_job) {
75
76 skip_comments(fstream);
77
78 for (cur_col = 1; cur_col < column; ++cur_col) {
79 /* discard input until we get to the column we want */
80 fscanf(fstream, "%*s,");
81 }
82
83 /* get the desired exec. time */
84 if (1 != fscanf(fstream, "%lf", (*exec_times)+cur_job)) {
85 fprintf(stderr, "invalid execution time near line %d\n",
86 cur_job);
87 exit(EXIT_FAILURE);
88 }
89
90 skip_to_next_line(fstream);
91 }
92
93 assert(cur_job == *num_jobs);
94 fclose(fstream);
36} 95}
37 96
38#define NUMS 4096 97#define NUMS 4096
39static int num[NUMS]; 98static int num[NUMS];
40static double loop_length = 1.0;
41static char* progname; 99static char* progname;
42 100
43static int loop_once(void) 101static int loop_once(void)
@@ -48,74 +106,40 @@ static int loop_once(void)
48 return j; 106 return j;
49} 107}
50 108
51static int loop_for(double exec_time) 109static int loop_for(double exec_time, double emergency_exit)
52{ 110{
53 double t = 0; 111 double last_loop = 0, loop_start;
54 int tmp = 0; 112 int tmp = 0;
55/* while (t + loop_length < exec_time) { 113
56 tmp += loop_once();
57 t += loop_length;
58 }
59*/
60 double start = cputime(); 114 double start = cputime();
61 double now = cputime(); 115 double now = cputime();
62 while (now + loop_length < start + exec_time) { 116
117 while (now + last_loop < start + exec_time) {
118 loop_start = now;
63 tmp += loop_once(); 119 tmp += loop_once();
64 t += loop_length;
65 now = cputime(); 120 now = cputime();
121 last_loop = now - loop_start;
122 if (emergency_exit && wctime() > emergency_exit) {
123 /* Oops --- this should only be possible if the execution time tracking
124 * is broken in the LITMUS^RT kernel. */
125 fprintf(stderr, "!!! rtspin/%d emergency exit!\n", getpid());
126 fprintf(stderr, "Something is seriously wrong! Do not ignore this.\n");
127 break;
128 }
66 } 129 }
67 130
68 return tmp; 131 return tmp;
69} 132}
70 133
71static void fine_tune(double interval)
72{
73 double start, end, delta;
74
75 start = wctime();
76 loop_for(interval);
77 end = wctime();
78 delta = (end - start - interval) / interval;
79 if (delta != 0)
80 loop_length = loop_length / (1 - delta);
81}
82
83static void configure_loop(void)
84{
85 double start;
86
87 /* prime cache */
88 loop_once();
89 loop_once();
90 loop_once();
91
92 /* measure */
93 start = wctime();
94 loop_once(); /* hope we didn't get preempted */
95 loop_length = wctime();
96 loop_length -= start;
97
98 /* fine tune */
99 fine_tune(0.1);
100 fine_tune(0.1);
101 fine_tune(0.1);
102}
103
104static void show_loop_length(void)
105{
106 printf("%s/%d: loop_length=%f (%ldus)\n",
107 progname, getpid(), loop_length,
108 (long) (loop_length * 1000000));
109}
110 134
111static void debug_delay_loop(void) 135static void debug_delay_loop(void)
112{ 136{
113 double start, end, delay; 137 double start, end, delay;
114 show_loop_length(); 138
115 while (1) { 139 while (1) {
116 for (delay = 0.5; delay > 0.01; delay -= 0.01) { 140 for (delay = 0.5; delay > 0.01; delay -= 0.01) {
117 start = wctime(); 141 start = wctime();
118 loop_for(delay); 142 loop_for(delay, 0);
119 end = wctime(); 143 end = wctime();
120 printf("%6.4fs: looped for %10.8fs, delta=%11.8fs, error=%7.4f%%\n", 144 printf("%6.4fs: looped for %10.8fs, delta=%11.8fs, error=%7.4f%%\n",
121 delay, 145 delay,
@@ -126,16 +150,20 @@ static void debug_delay_loop(void)
126 } 150 }
127} 151}
128 152
129static int job(double exec_time) 153static int job(double exec_time, double program_end)
130{ 154{
131 loop_for(exec_time); 155 if (wctime() > program_end)
132 sleep_next_period(); 156 return 0;
133 return 0; 157 else {
158 loop_for(exec_time, program_end + 1);
159 sleep_next_period();
160 return 1;
161 }
134} 162}
135 163
136#define OPTSTR "p:c:m:wld:ve" 164#define OPTSTR "p:c:wldveo:f:s:m:"
137 165
138int main(int argc, char** argv) 166int main(int argc, char** argv)
139{ 167{
140 int ret; 168 int ret;
141 lt_t wcet; 169 lt_t wcet;
@@ -146,11 +174,14 @@ int main(int argc, char** argv)
146 int opt; 174 int opt;
147 int wait = 0; 175 int wait = 0;
148 int test_loop = 0; 176 int test_loop = 0;
149 int skip_config = 0; 177 int column = 1;
150 int verbose = 0; 178 const char *file = NULL;
151 int want_enforcement = 0; 179 int want_enforcement = 0;
152 double duration, start; 180 double duration = 0, start;
181 double *exec_times = NULL;
182 double scale = 1.0;
153 task_class_t class = RT_CLASS_HARD; 183 task_class_t class = RT_CLASS_HARD;
184 int cur_job, num_jobs;
154 crit_level_t crit = CRIT_LEVEL_C; 185 crit_level_t crit = CRIT_LEVEL_C;
155 186
156 progname = argv[0]; 187 progname = argv[0];
@@ -179,14 +210,14 @@ int main(int argc, char** argv)
179 case 'l': 210 case 'l':
180 test_loop = 1; 211 test_loop = 1;
181 break; 212 break;
182 case 'd': 213 case 'o':
183 /* manually configure delay per loop iteration 214 column = atoi(optarg);
184 * unit: microseconds */ 215 break;
185 loop_length = atof(optarg) / 1000000; 216 case 'f':
186 skip_config = 1; 217 file = optarg;
187 break; 218 break;
188 case 'v': 219 case 's':
189 verbose = 1; 220 scale = atof(optarg);
190 break; 221 break;
191 case ':': 222 case ':':
192 usage("Argument missing."); 223 usage("Argument missing.");
@@ -198,32 +229,50 @@ int main(int argc, char** argv)
198 } 229 }
199 } 230 }
200 231
201
202 if (!skip_config)
203 configure_loop();
204
205 if (test_loop) { 232 if (test_loop) {
206 debug_delay_loop(); 233 debug_delay_loop();
207 return 0; 234 return 0;
208 } 235 }
209 236
210 if (argc - optind < 3) 237 if (file) {
211 usage("Arguments missing."); 238 get_exec_times(file, column, &num_jobs, &exec_times);
239
240 if (argc - optind < 2)
241 usage("Arguments missing.");
242
243 for (cur_job = 0; cur_job < num_jobs; ++cur_job) {
244 /* convert the execution time to seconds */
245 duration += exec_times[cur_job] * 0.001;
246 }
247 } else {
248 /*
249 * if we're not reading from the CSV file, then we need
250 * three parameters
251 */
252 if (argc - optind < 3)
253 usage("Arguments missing.");
254 }
255
212 wcet_ms = atof(argv[optind + 0]); 256 wcet_ms = atof(argv[optind + 0]);
213 period_ms = atof(argv[optind + 1]); 257 period_ms = atof(argv[optind + 1]);
214 duration = atof(argv[optind + 2]); 258
215 wcet = wcet_ms * __NS_PER_MS; 259 wcet = wcet_ms * __NS_PER_MS;
216 period = period_ms * __NS_PER_MS; 260 period = period_ms * __NS_PER_MS;
217 if (wcet <= 0) 261 if (wcet <= 0)
218 usage("The worst-case execution time must be a " 262 usage("The worst-case execution time must be a "
219 "positive number."); 263 "positive number.");
220 if (period <= 0) 264 if (period <= 0)
221 usage("The period must be a positive number."); 265 usage("The period must be a positive number.");
222 if (wcet > period) { 266 if (!file && wcet > period) {
223 usage("The worst-case execution time must not " 267 usage("The worst-case execution time must not "
224 "exceed the period."); 268 "exceed the period.");
225 } 269 }
226 270
271 if (!file)
272 duration = atof(argv[optind + 2]);
273 else if (file && num_jobs > 1)
274 duration += period_ms * 0.001 * (num_jobs - 1);
275
227 if (migrate) { 276 if (migrate) {
228 ret = be_migrate_to(cpu); 277 ret = be_migrate_to(cpu);
229 if (ret < 0) 278 if (ret < 0)
@@ -238,9 +287,6 @@ int main(int argc, char** argv)
238 if (ret < 0) 287 if (ret < 0)
239 bail_out("could not setup rt task params"); 288 bail_out("could not setup rt task params");
240 289
241 if (verbose)
242 show_loop_length();
243
244 init_litmus(); 290 init_litmus();
245 291
246 ret = task_mode(LITMUS_RT_TASK); 292 ret = task_mode(LITMUS_RT_TASK);
@@ -255,9 +301,24 @@ int main(int argc, char** argv)
255 301
256 start = wctime(); 302 start = wctime();
257 303
258 while (start + duration > wctime()) { 304 if (file) {
259 job(wcet_ms * 0.0009); /* 90% wcet, in seconds */ 305 /* use times read from the CSV file */
306 for (cur_job = 0; cur_job < num_jobs; ++cur_job) {
307 /* convert job's length to seconds */
308 job(exec_times[cur_job] * 0.001 * scale,
309 start + duration);
310 }
311 } else {
312 /* conver to seconds and scale */
313 while (job(wcet_ms * 0.001 * scale, start + duration));
260 } 314 }
261 315
316 ret = task_mode(BACKGROUND_TASK);
317 if (ret != 0)
318 bail_out("could not become regular task (huh?)");
319
320 if (file)
321 free(exec_times);
322
262 return 0; 323 return 0;
263} 324}
diff --git a/inc/depend.makefile b/inc/depend.makefile
new file mode 100644
index 0000000..4d10534
--- /dev/null
+++ b/inc/depend.makefile
@@ -0,0 +1,22 @@
1# Generic dependency resolution. Part of liblitmus so that we don't have to
2# carry it around in every project using liblitmus.
3
4obj-all = ${sort ${foreach target,${all},${obj-${target}}}}
5
6# rule to generate dependency files
7%.d: %.c
8 @set -e; rm -f $@; \
9 $(CC) -MM $(CPPFLAGS) $< > $@.$$$$; \
10 sed 's,\($*\)\.o[ :]*,\1.o $@ : ,g' < $@.$$$$ > $@; \
11 rm -f $@.$$$$
12
13ifeq ($(MAKECMDGOALS),)
14MAKECMDGOALS += all
15endif
16
17ifneq ($(filter-out clean,$(MAKECMDGOALS)),)
18
19# Pull in dependencies.
20-include ${obj-all:.o=.d}
21
22endif
diff --git a/include/asm.h b/include/asm.h
deleted file mode 100644
index bc15fae..0000000
--- a/include/asm.h
+++ /dev/null
@@ -1,15 +0,0 @@
1/* liblitmus platform dependent includes */
2
3#ifndef ASM_H
4#define ASM_H
5
6#if defined(__i386__) || defined(__x86_64__)
7#include "asm_x86.h"
8#endif
9
10
11#ifdef __sparc__
12#include "asm_sparc.h"
13#endif
14
15#endif
diff --git a/include/asm_sparc.h b/include/asm_sparc.h
deleted file mode 100644
index 96c8049..0000000
--- a/include/asm_sparc.h
+++ /dev/null
@@ -1,92 +0,0 @@
1/* sparc64 assembly.
2 * Don't include directly, use asm.h instead.
3 *
4 * Most of this code comes straight out of the Linux kernel.
5 *
6 * The terms of the GPL v2 apply.
7 *
8 */
9
10#define membar_safe(type) \
11do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \
12 " membar " type "\n" \
13 "1:\n" \
14 : : : "memory"); \
15} while (0)
16
17#define mb() \
18 membar_safe("#LoadLoad | #LoadStore | #StoreStore | #StoreLoad")
19
20static inline void barrier(void)
21{
22 mb();
23}
24
25
26#define cpu_relax() barrier()
27
28static inline int
29cmpxchg(volatile int *m, int old, int new)
30{
31 __asm__ __volatile__("membar #StoreLoad | #LoadLoad\n"
32 "cas [%2], %3, %0\n\t"
33 "membar #StoreLoad | #StoreStore"
34 : "=&r" (new)
35 : "0" (new), "r" (m), "r" (old)
36 : "memory");
37
38 return new;
39}
40
41
42typedef struct { int counter; } atomic_t;
43
44#define ATOMIC_INIT(i) { (i) }
45
46/**
47 * atomic_read - read atomic variable
48 * @v: pointer of type atomic_t
49 *
50 * Atomically reads the value of @v.
51 */
52#define atomic_read(v) ((v)->counter)
53
54/**
55 * atomic_set - set atomic variable
56 * @v: pointer of type atomic_t
57 * @i: required value
58 *
59 * Atomically sets the value of @v to @i.
60 */
61#define atomic_set(v,i) (((v)->counter) = (i))
62
63
64/**
65 * atomic_add_return - add and return
66 * @v: pointer of type atomic_t
67 * @i: integer value to add
68 *
69 * Atomically adds @i to @v and returns @i + @v
70 */
71static __inline__ int atomic_add_return(int i, atomic_t *v)
72{
73 int old;
74 int ret;
75 goto first;
76 do {
77 cpu_relax();
78 first:
79 old = atomic_read(v);
80 ret = cmpxchg(&v->counter, old, old + i);
81 } while (ret != old);
82 return old + i;
83}
84
85static __inline__ void atomic_add(int i, atomic_t *v)
86{
87 atomic_add_return(i, v);
88}
89
90#define atomic_inc_return(v) (atomic_add_return(1,v))
91
92
diff --git a/include/asm_x86.h b/include/asm_x86.h
deleted file mode 100644
index ccc6cce..0000000
--- a/include/asm_x86.h
+++ /dev/null
@@ -1,144 +0,0 @@
1/* Intel ia32 assembly.
2 * Don't include directly, use asm.h instead.
3 *
4 * Most of this code comes straight out of the Linux kernel.
5 *
6 * The terms of the GPL v2 apply.
7 */
8
9static inline void barrier(void)
10{
11 __asm__ __volatile__("mfence": : :"memory");
12}
13
14static __inline__ void cpu_relax(void)
15{
16 __asm__ __volatile("pause");
17}
18
19/* please, use these only if you _really_ know what you're doing
20 * ... and remember iopl(3) first!! (include sys/io.h)
21 */
22static inline void cli(void) {
23 asm volatile("cli": : :"memory");
24}
25
26static inline void sti(void) {
27 asm volatile("sti": : :"memory");
28}
29
30typedef struct { int counter; } atomic_t;
31
32#ifdef __i386__
33
34#define ATOMIC_INIT(i) { (i) }
35
36/**
37 * atomic_read - read atomic variable
38 * @v: pointer of type atomic_t
39 *
40 * Atomically reads the value of @v.
41 */
42#define atomic_read(v) ((v)->counter)
43
44/**
45 * atomic_set - set atomic variable
46 * @v: pointer of type atomic_t
47 * @i: required value
48 *
49 * Atomically sets the value of @v to @i.
50 */
51#define atomic_set(v,i) (((v)->counter) = (i))
52
53static __inline__ void atomic_add(int i, atomic_t *v)
54{
55 __asm__ __volatile__(
56 "lock; addl %1,%0"
57 :"+m" (v->counter)
58 :"ir" (i));
59}
60
61/**
62 * atomic_add_return - add and return
63 * @v: pointer of type atomic_t
64 * @i: integer value to add
65 *
66 * Atomically adds @i to @v and returns @i + @v
67 */
68static __inline__ int atomic_add_return(int i, atomic_t *v)
69{
70 int __i;
71 __i = i;
72 __asm__ __volatile__(
73 "lock; xaddl %0, %1"
74 :"+r" (i), "+m" (v->counter)
75 : : "memory");
76 return i + __i;
77}
78
79#define atomic_inc_return(v) (atomic_add_return(1,v))
80
81#elif defined(__x86_64__)
82
83/* almost the same as i386, but extra care must be taken when
84 * specifying clobbered registers
85 */
86
87#define ATOMIC_INIT(i) { (i) }
88
89/**
90 * atomic_read - read atomic variable
91 * @v: pointer of type atomic_t
92 *
93 * Atomically reads the value of @v.
94 */
95static inline int atomic_read(const atomic_t *v)
96{
97 return v->counter;
98}
99
100/**
101 * atomic_set - set atomic variable
102 * @v: pointer of type atomic_t
103 * @i: required value
104 *
105 * Atomically sets the value of @v to @i.
106 */
107static inline void atomic_set(atomic_t *v, int i)
108{
109 v->counter = i;
110}
111
112/**
113 * atomic_add - add integer to atomic variable
114 * @i: integer value to add
115 * @v: pointer of type atomic_t
116 *
117 * Atomically adds @i to @v.
118 */
119static inline void atomic_add(int i, atomic_t *v)
120{
121 asm volatile("lock; addl %1,%0"
122 : "=m" (v->counter)
123 : "ir" (i), "m" (v->counter));
124}
125
126/**
127 * atomic_add_return - add and return
128 * @i: integer value to add
129 * @v: pointer of type atomic_t
130 *
131 * Atomically adds @i to @v and returns @i + @v
132 */
133static inline int atomic_add_return(int i, atomic_t *v)
134{
135 int __i = i;
136 asm volatile("lock; xaddl %0, %1"
137 : "+r" (i), "+m" (v->counter)
138 : : "memory");
139 return i + __i;
140}
141
142#define atomic_inc_return(v) (atomic_add_return(1, v))
143
144#endif
diff --git a/include/cycles.h b/include/cycles.h
deleted file mode 100644
index e9b0e11..0000000
--- a/include/cycles.h
+++ /dev/null
@@ -1,63 +0,0 @@
1#ifndef CYCLES_H
2#define CYCLES_H
3
4#ifdef __x86_64__
5
6#define rdtscll(val) do { \
7 unsigned int __a,__d; \
8 __asm__ __volatile__("rdtsc" : "=a" (__a), "=d" (__d)); \
9 (val) = ((unsigned long)__a) | (((unsigned long)__d)<<32); \
10} while(0)
11
12static __inline__ unsigned long long native_read_tsc(void)
13{
14 unsigned long long val;
15
16 __asm__ __volatile__("mfence":::"memory");
17 rdtscll(val);
18 __asm__ __volatile__("mfence":::"memory");
19
20 return val;
21}
22
23
24#define CYCLES_FMT "llu"
25
26typedef unsigned long long cycles_t;
27
28static inline cycles_t get_cycles(void)
29{
30 return native_read_tsc();
31}
32#elif defined __i386__
33static inline unsigned long long native_read_tsc(void) {
34 unsigned long long val;
35 __asm__ __volatile__("rdtsc" : "=A" (val));
36 return val;
37}
38
39typedef unsigned long long cycles_t;
40
41#define CYCLES_FMT "llu"
42
43static inline cycles_t get_cycles(void)
44{
45 return native_read_tsc();
46}
47#elif defined __sparc__
48
49#define NPT_BIT 63
50
51typedef unsigned long cycles_t;
52
53#define CYCLES_FMT "lu"
54
55static inline cycles_t get_cycles(void) {
56 unsigned long cycles = 0;
57 __asm__ __volatile__("rd %%asr24, %0" : "=r" (cycles));
58 return cycles & ~(1UL << NPT_BIT);
59}
60
61#endif
62
63#endif
diff --git a/include/litmus.h b/include/litmus.h
index 632b9e1..2c48766 100644
--- a/include/litmus.h
+++ b/include/litmus.h
@@ -5,15 +5,15 @@
5extern "C" { 5extern "C" {
6#endif 6#endif
7 7
8#include <sys/types.h>
9
8/* Include kernel header. 10/* Include kernel header.
9 * This is required for the rt_param 11 * This is required for the rt_param
10 * and control_page structures. 12 * and control_page structures.
11 */ 13 */
12#include <litmus/rt_param.h> 14#include "litmus/rt_param.h"
13
14#include <sys/types.h>
15 15
16#include "cycles.h" /* for null_call() */ 16#include "asm/cycles.h" /* for null_call() */
17 17
18typedef int pid_t; /* PID of a task */ 18typedef int pid_t; /* PID of a task */
19 19
@@ -61,13 +61,9 @@ static inline int od_open(int fd, obj_type_t type, int obj_id)
61 return od_openx(fd, type, obj_id, 0); 61 return od_openx(fd, type, obj_id, 0);
62} 62}
63 63
64/* FMLP binary semaphore support */ 64/* real-time locking protocol support */
65int fmlp_down(int od); 65int litmus_lock(int od);
66int fmlp_up(int od); 66int litmus_unlock(int od);
67
68/* SRP binary semaphore support */
69int srp_down(int od);
70int srp_up(int od);
71 67
72/* job control*/ 68/* job control*/
73int get_job_no(unsigned int* job_no); 69int get_job_no(unsigned int* job_no);
@@ -113,6 +109,12 @@ static inline lt_t ms2lt(unsigned long milliseconds)
113 return __NS_PER_MS * milliseconds; 109 return __NS_PER_MS * milliseconds;
114} 110}
115 111
112/* CPU time consumed so far in seconds */
113double cputime(void);
114
115/* wall-clock time in seconds */
116double wctime(void);
117
116/* semaphore allocation */ 118/* semaphore allocation */
117 119
118static inline int open_fmlp_sem(int fd, int name) 120static inline int open_fmlp_sem(int fd, int name)
diff --git a/setsched b/setsched
index bae94d4..df38558 100755
--- a/setsched
+++ b/setsched
@@ -1,10 +1,10 @@
1#!/bin/bash 1#!/bin/sh
2# 2#
3# setsched: facilitate changing the active scheduler plugin. 3# setsched: facilitate changing the active scheduler plugin.
4 4
5ADIR=/proc/litmus/active_plugin 5ADIR=/proc/litmus/active_plugin
6PDIR=/proc/litmus/plugins/loaded 6PDIR=/proc/litmus/plugins/loaded
7DIALOG=`which dialog` 7DIALOG=`which dialog 2> /dev/null`
8 8
9CHOICE=$1 9CHOICE=$1
10 10
@@ -22,10 +22,9 @@ if [ -z "$1" ]; then
22 # Check for presence of dialog, some distros don't install it by default. 22 # Check for presence of dialog, some distros don't install it by default.
23 if [ -z "$DIALOG" ]; then 23 if [ -z "$DIALOG" ]; then
24 echo "Error: The dialog utility cannot be found." 24 echo "Error: The dialog utility cannot be found."
25 echo " Please install the required package (dialog on Ubuntu)." 25 echo " Please install the required package (dialog on Ubuntu),"
26 echo " Note that you can also use setsched by passing the" 26 echo " or specify the desired plugin as a commandline argument,"
27 echo " desired scheduling plugins as a commandline argument," 27 echo " e.g., 'setsched GSN-EDF'."
28 echo " i.e., 'setsched GSN-EDF' activates GSN-EDF."
29 exit 2 28 exit 2
30 fi 29 fi
31 TMP=`mktemp` 30 TMP=`mktemp`
diff --git a/showsched b/showsched
index d6f6d3a..a936e05 100755
--- a/showsched
+++ b/showsched
@@ -1,4 +1,4 @@
1#!/bin/bash 1#!/bin/sh
2# 2#
3# showsched: show the currently active plugin and exit. 3# showsched: show the currently active plugin and exit.
4 4
diff --git a/src/clocks.c b/src/clocks.c
new file mode 100644
index 0000000..fcb94e5
--- /dev/null
+++ b/src/clocks.c
@@ -0,0 +1,23 @@
1#include <stdio.h>
2
3#include <sys/time.h>
4#include <time.h>
5
6/* CPU time consumed so far in seconds */
7double cputime(void)
8{
9 struct timespec ts;
10 int err;
11 err = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
12 if (err != 0)
13 perror("clock_gettime");
14 return (ts.tv_sec + 1E-9 * ts.tv_nsec);
15}
16
17/* wall-clock time in seconds */
18double wctime(void)
19{
20 struct timeval tv;
21 gettimeofday(&tv, NULL);
22 return (tv.tv_sec + 1E-6 * tv.tv_usec);
23}
diff --git a/src/kernel_iface.c b/src/kernel_iface.c
index afb6202..1426795 100644
--- a/src/kernel_iface.c
+++ b/src/kernel_iface.c
@@ -8,7 +8,6 @@
8 8
9#include "litmus.h" 9#include "litmus.h"
10#include "internal.h" 10#include "internal.h"
11#include "asm.h"
12 11
13#define LITMUS_CTRL_DEVICE "/dev/litmus/ctrl" 12#define LITMUS_CTRL_DEVICE "/dev/litmus/ctrl"
14#define CTRL_PAGES 1 13#define CTRL_PAGES 1
@@ -66,7 +65,7 @@ void exit_np(void)
66{ 65{
67 if (likely(ctrl_page != NULL) && --ctrl_page->np_flag == 0) { 66 if (likely(ctrl_page != NULL) && --ctrl_page->np_flag == 0) {
68 /* became preemptive, let's check for delayed preemptions */ 67 /* became preemptive, let's check for delayed preemptions */
69 barrier(); 68 __sync_synchronize();
70 if (ctrl_page->delayed_preemption) 69 if (ctrl_page->delayed_preemption)
71 sched_yield(); 70 sched_yield();
72 } 71 }
diff --git a/src/litmus.c b/src/litmus.c
index 84e844c..fe63bad 100644
--- a/src/litmus.c
+++ b/src/litmus.c
@@ -80,7 +80,7 @@ int sporadic_task_ns(lt_t e, lt_t p, lt_t phase,
80 param.period = p; 80 param.period = p;
81 param.cpu = cpu; 81 param.cpu = cpu;
82 param.cls = cls; 82 param.cls = cls;
83 param.crit = crit; 83 param.crit = crit;
84 param.phase = phase; 84 param.phase = phase;
85 param.budget_policy = budget_policy; 85 param.budget_policy = budget_policy;
86 86
diff --git a/src/syscalls.c b/src/syscalls.c
index 77a6277..d800141 100644
--- a/src/syscalls.c
+++ b/src/syscalls.c
@@ -1,13 +1,16 @@
1/* To get syscall() we need to define _GNU_SOURCE 1/* To get syscall() we need to define _GNU_SOURCE
2 * in modern glibc versions. 2 * in modern glibc versions.
3 */ 3 */
4
5/* imported from the kernel source tree */
6#include "asm/unistd.h"
7
8/* for syscall() */
4#include <unistd.h> 9#include <unistd.h>
5#include <linux/unistd.h>
6#include <sys/types.h>
7 10
8#include "litmus.h" 11//#include <sys/types.h>
9 12
10struct np_flag; 13#include "litmus.h"
11 14
12/* Syscall stub for setting RT mode and scheduling options */ 15/* Syscall stub for setting RT mode and scheduling options */
13 16
@@ -41,24 +44,14 @@ int od_close(int od)
41 return syscall(__NR_od_close, od); 44 return syscall(__NR_od_close, od);
42} 45}
43 46
44int fmlp_down(int od) 47int litmus_lock(int od)
45{
46 return syscall(__NR_fmlp_down, od);
47}
48
49int fmlp_up(int od)
50{
51 return syscall(__NR_fmlp_up, od);
52}
53
54int srp_down(int od)
55{ 48{
56 return syscall(__NR_srp_down, od); 49 return syscall(__NR_litmus_lock, od);
57} 50}
58 51
59int srp_up(int od) 52int litmus_unlock(int od)
60{ 53{
61 return syscall(__NR_srp_up, od); 54 return syscall(__NR_litmus_unlock, od);
62} 55}
63 56
64int get_job_no(unsigned int *job_no) 57int get_job_no(unsigned int *job_no)
diff --git a/tests/core_api.c b/tests/core_api.c
index d858f1f..7487c1c 100644
--- a/tests/core_api.c
+++ b/tests/core_api.c
@@ -1,5 +1,8 @@
1#include "tests.h" 1#include <sys/wait.h> /* for waitpid() */
2#include <unistd.h>
3#include <stdio.h>
2 4
5#include "tests.h"
3#include "litmus.h" 6#include "litmus.h"
4 7
5 8
@@ -49,3 +52,40 @@ TESTCASE(job_control_non_rt, ALL,
49 52
50 SYSCALL_FAILS( EPERM, get_job_no(&job_no) ); 53 SYSCALL_FAILS( EPERM, get_job_no(&job_no) );
51} 54}
55
56
57TESTCASE(rt_fork_non_rt, LITMUS,
58 "children of RT tasks are not automatically RT tasks")
59{
60 unsigned int pid, job_no;
61 int status;
62
63 SYSCALL( sporadic_partitioned(10, 100, 0) );
64 SYSCALL( task_mode(LITMUS_RT_TASK) );
65
66 pid = fork();
67
68 ASSERT( pid != -1 );
69
70 if (pid == 0) {
71 /* child */
72
73 SYSCALL_FAILS( EINVAL, sleep_next_period() );
74 SYSCALL_FAILS( EINVAL, wait_for_job_release(0) );
75 SYSCALL_FAILS( EPERM, get_job_no(&job_no) );
76
77 exit(0);
78 } else {
79 /* parent */
80
81 SYSCALL( sleep_next_period() );
82 SYSCALL( wait_for_job_release(20) );
83 SYSCALL( get_job_no(&job_no) );
84
85 SYSCALL( task_mode(BACKGROUND_TASK) );
86
87 SYSCALL( waitpid(pid, &status, 0) );
88
89 ASSERT(WEXITSTATUS(status) == 0);
90 }
91}
diff --git a/tests/fdso.c b/tests/fdso.c
index c95a578..8a2a0d0 100644
--- a/tests/fdso.c
+++ b/tests/fdso.c
@@ -1,3 +1,5 @@
1#include <sys/wait.h> /* for waitpid() */
2
1#include <fcntl.h> 3#include <fcntl.h>
2#include <unistd.h> 4#include <unistd.h>
3 5
@@ -18,7 +20,7 @@ TESTCASE(fmlp_not_active, C_EDF | PFAIR | LINUX,
18 20
19 ASSERT(fd != -1); 21 ASSERT(fd != -1);
20 22
21 SYSCALL_FAILS(EBUSY, open_fmlp_sem(fd, 0) ); 23 SYSCALL_FAILS(ENXIO, open_fmlp_sem(fd, 0) );
22 24
23 SYSCALL( close(fd) ); 25 SYSCALL( close(fd) );
24 26
@@ -29,16 +31,16 @@ TESTCASE(fmlp_not_active, C_EDF | PFAIR | LINUX,
29TESTCASE(invalid_od, ALL, 31TESTCASE(invalid_od, ALL,
30 "reject invalid object descriptors") 32 "reject invalid object descriptors")
31{ 33{
32 SYSCALL_FAILS( EINVAL, fmlp_down(3) ); 34 SYSCALL_FAILS( EINVAL, litmus_lock(3) );
33 35
34 SYSCALL_FAILS( EINVAL, fmlp_up(3) ); 36 SYSCALL_FAILS( EINVAL, litmus_unlock(3) );
35 37
36 SYSCALL_FAILS( EINVAL, od_close(3) ); 38 SYSCALL_FAILS( EINVAL, od_close(3) );
37 39
38 40
39 SYSCALL_FAILS( EINVAL, fmlp_down(-1) ); 41 SYSCALL_FAILS( EINVAL, litmus_lock(-1) );
40 42
41 SYSCALL_FAILS( EINVAL, fmlp_up(-1) ); 43 SYSCALL_FAILS( EINVAL, litmus_unlock(-1) );
42 44
43 SYSCALL_FAILS( EINVAL, od_close(-1) ); 45 SYSCALL_FAILS( EINVAL, od_close(-1) );
44} 46}
@@ -59,23 +61,34 @@ TESTCASE(not_inherit_od, GSN_EDF | PSN_EDF,
59 61
60 SYSCALL( od = open_fmlp_sem(fd, 0) ); 62 SYSCALL( od = open_fmlp_sem(fd, 0) );
61 63
62 SYSCALL( fmlp_down(od) );
63
64 SYSCALL( fmlp_up(od) );
65
66 pid = fork(); 64 pid = fork();
67 65
68 ASSERT( pid != -1 ); 66 ASSERT( pid != -1 );
69 67
68 /* must be an RT task to lock at all */
69 SYSCALL( sporadic_partitioned(10, 100, 0) );
70 SYSCALL( task_mode(LITMUS_RT_TASK) );
71
70 if (pid == 0) { 72 if (pid == 0) {
71 /* child */ 73 /* child */
72 SYSCALL_FAILS(EINVAL, fmlp_down(od) ); 74 SYSCALL_FAILS(EINVAL, litmus_lock(od) );
73 SYSCALL_FAILS(EINVAL, fmlp_up(od) ); 75 SYSCALL_FAILS(EINVAL, litmus_unlock(od) );
76
77 SYSCALL( task_mode(BACKGROUND_TASK) );
78
74 exit(0); 79 exit(0);
75 } else { 80 } else {
76 SYSCALL( fmlp_down(od) ); 81
77 SYSCALL( fmlp_up(od) ); 82 SYSCALL( litmus_lock(od) );
83 SYSCALL( litmus_unlock(od) );
84
85 SYSCALL( litmus_lock(od) );
86 SYSCALL( litmus_unlock(od) );
87
88 SYSCALL( task_mode(BACKGROUND_TASK) );
89
78 SYSCALL( waitpid(pid, &status, 0) ); 90 SYSCALL( waitpid(pid, &status, 0) );
91
79 ASSERT(WEXITSTATUS(status) == 0); 92 ASSERT(WEXITSTATUS(status) == 0);
80 } 93 }
81 94
diff --git a/tests/locks.c b/tests/locks.c
new file mode 100644
index 0000000..65b932a
--- /dev/null
+++ b/tests/locks.c
@@ -0,0 +1,110 @@
1#include <fcntl.h>
2#include <unistd.h>
3#include <stdio.h>
4
5#include "tests.h"
6#include "litmus.h"
7
8
9TESTCASE(not_lock_fmlp_be, GSN_EDF | PSN_EDF,
10 "don't let best-effort tasks lock FMLP semaphores")
11{
12 int fd, od;
13
14 SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) );
15
16 SYSCALL( od = open_fmlp_sem(fd, 0) );
17
18 /* BE tasks may not lock FMLP semaphores */
19 SYSCALL_FAILS(EPERM, litmus_lock(od) );
20
21 /* tasks may not unlock resources they don't own */
22 SYSCALL_FAILS(EINVAL, litmus_unlock(od) );
23
24 SYSCALL( od_close(od) );
25
26 SYSCALL( close(fd) );
27
28 SYSCALL( remove(".fmlp_locks") );
29
30}
31
32TESTCASE(not_lock_srp_be, PSN_EDF,
33 "don't let best-effort tasks open SRP semaphores")
34{
35 int fd, od;
36
37 SYSCALL( fd = open(".srp_locks", O_RDONLY | O_CREAT) );
38
39 /* BE tasks may not open SRP semaphores */
40
41 SYSCALL_FAILS(EPERM, od = open_srp_sem(fd, 0) );
42
43 SYSCALL( close(fd) );
44
45 SYSCALL( remove(".srp_locks") );
46
47}
48
49TESTCASE(lock_srp, PSN_EDF,
50 "SRP acquisition and release")
51{
52 int fd, od;
53
54 SYSCALL( fd = open(".srp_locks", O_RDONLY | O_CREAT) );
55
56 SYSCALL( sporadic_partitioned(10, 100, 0) );
57 SYSCALL( task_mode(LITMUS_RT_TASK) );
58
59 SYSCALL( od = open_srp_sem(fd, 0) );
60
61 SYSCALL( litmus_lock(od) );
62 SYSCALL( litmus_unlock(od) );
63
64 SYSCALL( litmus_lock(od) );
65 SYSCALL( litmus_unlock(od) );
66
67 SYSCALL( litmus_lock(od) );
68 SYSCALL( litmus_unlock(od) );
69
70 /* tasks may not unlock resources they don't own */
71 SYSCALL_FAILS(EINVAL, litmus_unlock(od) );
72
73 SYSCALL( od_close(od) );
74
75 SYSCALL( close(fd) );
76
77 SYSCALL( remove(".srp_locks") );
78}
79
80
81TESTCASE(lock_fmlp, PSN_EDF | GSN_EDF,
82 "FMLP acquisition and release")
83{
84 int fd, od;
85
86 SYSCALL( fd = open(".fmlp_locks", O_RDONLY | O_CREAT) );
87
88 SYSCALL( sporadic_partitioned(10, 100, 0) );
89 SYSCALL( task_mode(LITMUS_RT_TASK) );
90
91 SYSCALL( od = open_fmlp_sem(fd, 0) );
92
93 SYSCALL( litmus_lock(od) );
94 SYSCALL( litmus_unlock(od) );
95
96 SYSCALL( litmus_lock(od) );
97 SYSCALL( litmus_unlock(od) );
98
99 SYSCALL( litmus_lock(od) );
100 SYSCALL( litmus_unlock(od) );
101
102 /* tasks may not unlock resources they don't own */
103 SYSCALL_FAILS(EINVAL, litmus_unlock(od) );
104
105 SYSCALL( od_close(od) );
106
107 SYSCALL( close(fd) );
108
109 SYSCALL( remove(".fmlp_locks") );
110}
diff --git a/tests/make_catalog.py b/tests/make_catalog.py
index 75b6aca..96f9b23 100755
--- a/tests/make_catalog.py
+++ b/tests/make_catalog.py
@@ -63,6 +63,7 @@ def create_tc_tables(out=sys.stdout):
63 plugins.add(p) 63 plugins.add(p)
64 64
65 plugins.discard('ALL') 65 plugins.discard('ALL')
66 plugins.discard('LITMUS')
66 67
67 _('#include "tests.h"') 68 _('#include "tests.h"')
68 69
@@ -78,7 +79,9 @@ def create_tc_tables(out=sys.stdout):
78 count = 0 79 count = 0
79 _('int %s_TESTS[] = {' % p) 80 _('int %s_TESTS[] = {' % p)
80 for (i, tc) in enumerate(tests): 81 for (i, tc) in enumerate(tests):
81 if p in tc.plugins or 'ALL' in tc.plugins: 82 if p in tc.plugins or \
83 'ALL' in tc.plugins or \
84 'LITMUS' in tc.plugins and p != 'LINUX':
82 _('\t%d,' % i) 85 _('\t%d,' % i)
83 count += 1 86 count += 1
84 _('};') 87 _('};')
diff --git a/tests/runner.c b/tests/runner.c
index f2e42b2..ccf8d46 100644
--- a/tests/runner.c
+++ b/tests/runner.c
@@ -7,8 +7,8 @@
7#include <stdio.h> 7#include <stdio.h>
8 8
9 9
10/* auto generated by SConstruct */ 10/* auto generated by Makefile */
11#include "__test_catalog.inc" 11#include "../test_catalog.inc"
12 12
13#include "litmus.h" 13#include "litmus.h"
14 14