diff options
-rw-r--r-- | .gitignore | 10 | ||||
-rw-r--r-- | INSTALL | 56 | ||||
-rw-r--r-- | Makefile | 286 | ||||
-rw-r--r-- | README | 17 | ||||
-rw-r--r-- | SConstruct | 232 | ||||
-rw-r--r-- | arch/arm/include/asm/cycles.h | 23 | ||||
-rw-r--r-- | arch/sparc/include/asm/cycles.h | 16 | ||||
-rw-r--r-- | arch/x86/include/asm/cycles.h | 30 | ||||
-rw-r--r-- | arch/x86/include/asm/irq.h | 15 | ||||
-rw-r--r-- | bin/cycles.c | 2 | ||||
-rw-r--r-- | bin/null_call.c | 3 | ||||
-rw-r--r-- | bin/rtspin.c | 261 | ||||
-rw-r--r-- | inc/depend.makefile | 22 | ||||
-rw-r--r-- | include/asm.h | 15 | ||||
-rw-r--r-- | include/asm_sparc.h | 92 | ||||
-rw-r--r-- | include/asm_x86.h | 144 | ||||
-rw-r--r-- | include/cycles.h | 63 | ||||
-rw-r--r-- | include/litmus.h | 24 | ||||
-rwxr-xr-x | setsched | 11 | ||||
-rwxr-xr-x | showsched | 2 | ||||
-rw-r--r-- | src/clocks.c | 23 | ||||
-rw-r--r-- | src/kernel_iface.c | 3 | ||||
-rw-r--r-- | src/litmus.c | 2 | ||||
-rw-r--r-- | src/syscalls.c | 29 | ||||
-rw-r--r-- | tests/core_api.c | 42 | ||||
-rw-r--r-- | tests/fdso.c | 39 | ||||
-rw-r--r-- | tests/locks.c | 110 | ||||
-rwxr-xr-x | tests/make_catalog.py | 5 | ||||
-rw-r--r-- | tests/runner.c | 4 |
29 files changed, 845 insertions, 736 deletions
@@ -2,8 +2,11 @@ | |||
2 | *.o | 2 | *.o |
3 | *.a | 3 | *.a |
4 | 4 | ||
5 | |||
6 | |||
5 | # generated files | 7 | # generated files |
6 | tests/__test_catalog.inc | 8 | tests/test_catalog.inc |
9 | *.d | ||
7 | 10 | ||
8 | # executables | 11 | # executables |
9 | runtests | 12 | runtests |
@@ -20,8 +23,5 @@ rtspin | |||
20 | cycles | 23 | cycles |
21 | measure_syscall | 24 | measure_syscall |
22 | 25 | ||
23 | # scons files | 26 | # build system files |
24 | .sconsign.dblite | ||
25 | .sconf_temp/* | ||
26 | config.log | ||
27 | .config | 27 | .config |
@@ -0,0 +1,56 @@ | |||
1 | |||
2 | Liblitmus Installation Instructions | ||
3 | =================================== | ||
4 | |||
5 | Dependencies | ||
6 | ------------ | ||
7 | |||
8 | Liblitmus has no dependencies besides the kernel. During compilation, the | ||
9 | Makefile will attempt to copy required headers from the kernel source tree into | ||
10 | the library source tree. | ||
11 | |||
12 | |||
13 | Configuration | ||
14 | ------------- | ||
15 | |||
16 | The build system reads a local configuration file named '.config' (just like the | ||
17 | kernel, but much simpler). There are three variables that affect the | ||
18 | compilation 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 | |||
33 | Makefile 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 | |||
@@ -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 |
2 | host-arch := $(shell uname -m | \ | ||
3 | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/) | ||
2 | 4 | ||
3 | all-32: | 5 | # ############################################################################## |
4 | echo "Legacy warning: Building is done with scons." | 6 | # User variables |
5 | ARCH=x86 scons | ||
6 | all-64: | ||
7 | ARCH=x86_64 scons | ||
8 | 7 | ||
9 | all-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? | ||
12 | ARCH ?= ${host-arch} | ||
13 | |||
14 | # LITMUS_KERNEL -- where to find the litmus kernel? | ||
15 | LITMUS_KERNEL ?= ../litmus2010 | ||
16 | |||
17 | |||
18 | # ############################################################################## | ||
19 | # Internal configuration. | ||
20 | |||
21 | # compiler flags | ||
22 | flags-debug = -Wall -Werror -g -Wdeclaration-after-statement | ||
23 | flags-api = -D_XOPEN_SOURCE=600 -D_GNU_SOURCE | ||
24 | |||
25 | # architecture-specific flags | ||
26 | flags-i386 = -m32 | ||
27 | flags-x86_64 = -m64 | ||
28 | flags-sparc64 = -mcpu=v9 -m64 | ||
29 | # default: none | ||
30 | |||
31 | # name of the directory that has the arch headers in the Linux source | ||
32 | include-i386 = x86 | ||
33 | include-x86_64 = x86 | ||
34 | include-sparc64 = sparc | ||
35 | # default: the arch name | ||
36 | include-${ARCH} ?= ${ARCH} | ||
37 | |||
38 | # name of the file(s) that holds the actual system call numbers | ||
39 | unistd-i386 = unistd.h unistd_32.h | ||
40 | unistd-x86_64 = unistd.h unistd_64.h | ||
41 | # default: unistd.h | ||
42 | unistd-${ARCH} ?= unistd.h | ||
43 | |||
44 | # by default we use the local version | ||
45 | LIBLITMUS ?= . | ||
46 | |||
47 | # where to find header files | ||
48 | headers = -I${LIBLITMUS}/include -I${LIBLITMUS}/arch/${include-${ARCH}}/include | ||
49 | |||
50 | # combine options | ||
51 | CPPFLAGS = ${flags-api} ${flags-${ARCH}} -DARCH=${ARCH} ${headers} | ||
52 | CFLAGS = ${flags-debug} | ||
53 | LDFLAGS = ${flags-${ARCH}} | ||
54 | |||
55 | # how to link against liblitmus | ||
56 | liblitmus-flags = -L${LIBLITMUS} -llitmus | ||
57 | |||
58 | # Force gcc instead of cc, but let the user specify a more specific version if | ||
59 | # desired. | ||
60 | ifeq (${CC},cc) | ||
61 | CC = gcc | ||
62 | endif | ||
63 | |||
64 | # incorporate cross-compiler (if any) | ||
65 | CC := ${CROSS_COMPILE}${CC} | ||
66 | LD := ${CROSS_COMPILE}${LD} | ||
67 | AR := ${CROSS_COMPILE}${AR} | ||
68 | |||
69 | # ############################################################################## | ||
70 | # Targets | ||
71 | |||
72 | all = lib ${rt-apps} | ||
73 | rt-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 | |||
78 | all: ${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. | ||
84 | inc/config.makefile: LIBLITMUS = $${LIBLITMUS} | ||
85 | inc/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 | |||
97 | dump-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 | |||
114 | help: | ||
115 | @cat INSTALL | ||
11 | 116 | ||
12 | clean: | 117 | clean: |
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 | ||
125 | TAGS: | ||
126 | @echo TAGS | ||
127 | @find . -type f -and -iname '*.[ch]' | xargs etags | ||
128 | |||
129 | # Vim Tags | ||
130 | tags: | ||
131 | @echo tags | ||
132 | @find . -type f -and -iname '*.[ch]' | xargs ctags | ||
133 | |||
134 | # cscope DB | ||
135 | cscope: | ||
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 | ||
146 | include/litmus/%.h: ${LITMUS_KERNEL}/include/litmus/%.h | ||
147 | @mkdir -p ${dir $@} | ||
148 | cp $< $@ | ||
149 | |||
150 | # asm headers | ||
151 | arch/${include-${ARCH}}/include/asm/%.h: \ | ||
152 | ${LITMUS_KERNEL}/arch/${include-${ARCH}}/include/asm/%.h | ||
153 | @mkdir -p ${dir $@} | ||
154 | cp $< $@ | ||
155 | |||
156 | litmus-headers = include/litmus/rt_param.h include/litmus/unistd_32.h \ | ||
157 | include/litmus/unistd_64.h | ||
158 | |||
159 | unistd-headers = \ | ||
160 | $(foreach file,${unistd-${ARCH}},arch/${include-${ARCH}}/include/asm/$(file)) | ||
161 | |||
162 | |||
163 | imported-headers = ${litmus-headers} ${unistd-headers} | ||
164 | |||
165 | # Let's not copy these twice. | ||
166 | .SECONDARY: ${imported-headers} | ||
167 | |||
168 | # ############################################################################## | ||
169 | # liblitmus | ||
170 | |||
171 | lib: liblitmus.a | ||
172 | |||
173 | # all .c file in src/ are linked into liblitmus | ||
174 | vpath %.c src/ | ||
175 | obj-lib = $(patsubst src/%.c,%.o,$(wildcard src/*.c)) | ||
176 | |||
177 | liblitmus.a: ${obj-lib} | ||
178 | ${AR} rcs $@ $+ | ||
179 | |||
180 | # ############################################################################## | ||
181 | # Tests suite. | ||
182 | |||
183 | # tests are found in tests/ | ||
184 | vpath %.c tests/ | ||
185 | |||
186 | src-runtests = $(wildcard tests/*.c) | ||
187 | obj-runtests = $(patsubst tests/%.c,%.o,${src-runtests}) | ||
188 | |||
189 | # generate list of tests automatically | ||
190 | test_catalog.inc: $(filter-out tests/runner.c,${src-runtests}) | ||
191 | tests/make_catalog.py $+ > $@ | ||
192 | |||
193 | tests/runner.c: test_catalog.inc | ||
194 | |||
195 | |||
196 | # ############################################################################## | ||
197 | # Tools that link with liblitmus | ||
198 | |||
199 | # these source files are found in bin/ | ||
200 | vpath %.c bin/ | ||
201 | |||
202 | obj-cycles = cycles.o | ||
203 | |||
204 | obj-base_task = base_task.o | ||
205 | |||
206 | obj-base_mt_task = base_mt_task.o | ||
207 | ldf-base_mt_task = -pthread | ||
208 | |||
209 | obj-rt_launch = rt_launch.o common.o | ||
210 | |||
211 | obj-rtspin = rtspin.o common.o | ||
212 | lib-rtspin = -lrt | ||
213 | |||
214 | obj-release_ts = release_ts.o | ||
215 | |||
216 | obj-measure_syscall = null_call.o | ||
217 | lib-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 | |||
229 | vpath %.c bin/ src/ tests/ | ||
230 | |||
231 | obj-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 | |||
240 | ifeq ($(MAKECMDGOALS),) | ||
241 | MAKECMDGOALS += all | ||
242 | endif | ||
243 | |||
244 | ifneq ($(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. | ||
250 | config-ok := $(shell test -d "${LITMUS_KERNEL}" || echo invalid path. ) | ||
251 | config-ok += $(shell test -f "${LITMUS_KERNEL}/${word 1,${litmus-headers}}" \ | ||
252 | || echo cannot find header. ) | ||
253 | ifneq ($(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) | ||
259 | endif | ||
260 | |||
261 | kernel-unistd-hdrs := $(foreach file,${unistd-headers},${LITMUS_KERNEL}/$(file)) | ||
262 | hdr-ok := $(shell egrep '\#include ["<]litmus/unistd' ${kernel-unistd-hdrs} ) | ||
263 | ifeq ($(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) | ||
266 | endif | ||
267 | |||
268 | config-ok := $(shell test -f "${LITMUS_KERNEL}/${word 1,${unistd-headers}}" \ | ||
269 | || echo fail ) | ||
270 | ifneq ($(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) | ||
276 | endif | ||
277 | |||
278 | endif | ||
15 | 279 | ||
16 | purge: clean | ||
17 | rm -rf .sconf_temp .sconsign.dblite | ||
@@ -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 | |||
60 | Install | ||
61 | ======= | ||
62 | The library and the included tools must be compiled from source. | ||
63 | Liblitmus uses SCons as the build system. For details see: | ||
64 | |||
65 | http://www.scons.org/ | ||
66 | |||
67 | To compile the library just execute the command 'scons' without | ||
68 | arguments. | ||
69 | |||
70 | x86_64->ia32 cross compilation is possible by specifying ARCH=i386 on the | ||
71 | command 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 @@ | |||
1 | Help(""" | ||
2 | ============================================= | ||
3 | liblitmus --- The LITMUS^RT Userspace Library | ||
4 | |||
5 | There are a number of user-configurable build | ||
6 | variables. These can either be set on the | ||
7 | command line (e.g., scons ARCH=x86) or read | ||
8 | from a local configuration file (.config). | ||
9 | |||
10 | Run 'scons --dump-config' to see the final | ||
11 | build configuration. | ||
12 | |||
13 | """) | ||
14 | |||
15 | import os | ||
16 | (ostype, _, _, _, arch) = os.uname() | ||
17 | |||
18 | # sanity check | ||
19 | if ostype != 'Linux': | ||
20 | print 'Error: Building liblitmus is only supported on Linux.' | ||
21 | Exit(1) | ||
22 | |||
23 | |||
24 | # ##################################################################### | ||
25 | # Internal configuration. | ||
26 | DEBUG_FLAGS = '-Wall -g -Wdeclaration-after-statement' | ||
27 | API_FLAGS = '-D_XOPEN_SOURCE=600 -D_GNU_SOURCE' | ||
28 | X86_32_FLAGS = '-m32' | ||
29 | X86_64_FLAGS = '-m64' | ||
30 | V9_FLAGS = '-mcpu=v9 -m64' | ||
31 | |||
32 | SUPPORTED_ARCHS = { | ||
33 | 'sparc64' : V9_FLAGS, | ||
34 | 'x86' : X86_32_FLAGS, | ||
35 | 'x86_64' : X86_64_FLAGS, | ||
36 | } | ||
37 | |||
38 | ARCH_ALIAS = { | ||
39 | 'i686' : 'x86' | ||
40 | } | ||
41 | |||
42 | # name of the directory that has the arch headers in the Linux source | ||
43 | INCLUDE_ARCH = { | ||
44 | 'sparc64' : 'sparc', | ||
45 | 'x86' : 'x86', | ||
46 | 'x86_64' : 'x86', | ||
47 | } | ||
48 | |||
49 | INCLUDE_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 | |||
61 | vars = Variables('.config', ARGUMENTS) | ||
62 | |||
63 | vars.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 | |||
74 | AddOption('--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 | |||
83 | env = Environment(variables = vars) | ||
84 | |||
85 | # Check what we are building for. | ||
86 | arch = env['ARCH'] | ||
87 | |||
88 | # replace if the arch has an alternative name | ||
89 | if arch in ARCH_ALIAS: | ||
90 | arch = ARCH_ALIAS[arch] | ||
91 | env['ARCH'] = arch | ||
92 | |||
93 | # Get include directory for arch. | ||
94 | env['INCLUDE_ARCH'] = INCLUDE_ARCH[arch] | ||
95 | |||
96 | arch_flags = Split(SUPPORTED_ARCHS[arch]) | ||
97 | dbg_flags = Split(DEBUG_FLAGS) | ||
98 | api_flags = Split(API_FLAGS) | ||
99 | |||
100 | # Set up environment | ||
101 | env.Replace( | ||
102 | CC = 'gcc', | ||
103 | CPPPATH = INCLUDE_DIRS, | ||
104 | CCFLAGS = dbg_flags + api_flags + arch_flags, | ||
105 | LINKFLAGS = arch_flags, | ||
106 | ) | ||
107 | |||
108 | def 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 | |||
118 | if 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 | |||
128 | def CheckSyscallNr(context): | ||
129 | context.Message('Checking for LITMUS^RT syscall numbers... ') | ||
130 | nrSrc = """ | ||
131 | #include <linux/unistd.h> | ||
132 | int 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 | |||
142 | def 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 | ||
154 | if 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 | ||
179 | rt = env.Clone( | ||
180 | LIBS = Split('litmus rt'), | ||
181 | LIBPATH = '.' | ||
182 | ) | ||
183 | rt.Append(LINKFLAGS = '-static') | ||
184 | |||
185 | |||
186 | # link with math lib | ||
187 | rtm = rt.Clone() | ||
188 | rtm.Append(LIBS = ['m']) | ||
189 | |||
190 | # multithreaded real-time tasks | ||
191 | mtrt = rt.Clone() | ||
192 | mtrt.Append(LINKFLAGS = '-pthread') | ||
193 | |||
194 | # ##################################################################### | ||
195 | # Targets: liblitmus | ||
196 | # All the files in src/ are part of the library. | ||
197 | env.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 | ||
203 | env.Program('cycles', 'bin/cycles.c') | ||
204 | |||
205 | # ##################################################################### | ||
206 | # Targets: tools that depend on liblitmus | ||
207 | rt.Program('base_task', 'bin/base_task.c') | ||
208 | mtrt.Program('base_mt_task', 'bin/base_mt_task.c') | ||
209 | rt.Program('rt_launch', ['bin/rt_launch.c', 'bin/common.c']) | ||
210 | rt.Program('rtspin', ['bin/rtspin.c', 'bin/common.c']) | ||
211 | rt.Program('release_ts', 'bin/release_ts.c') | ||
212 | rtm.Program('measure_syscall', 'bin/null_call.c') | ||
213 | |||
214 | |||
215 | # ##################################################################### | ||
216 | # Test suite. | ||
217 | |||
218 | mkc = Builder(action = 'tests/make_catalog.py $SOURCES > $TARGET') | ||
219 | test = mtrt.Clone() | ||
220 | test.Append(BUILDERS = {'TestCatalog' : mkc}) | ||
221 | test.Append(CPPPATH = ['tests/']) | ||
222 | |||
223 | catalog = test.TestCatalog('tests/__test_catalog.inc', Glob('tests/*.c')) | ||
224 | test.Program('runtests', Glob('tests/*.c')) | ||
225 | |||
226 | # ##################################################################### | ||
227 | # Additional Help | ||
228 | |||
229 | Help("Build Variables\n") | ||
230 | Help("---------------\n") | ||
231 | Help(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 | |||
4 | typedef unsigned long cycles_t; | ||
5 | |||
6 | #define CYCLES_FMT "lu" | ||
7 | |||
8 | /* system call wrapper */ | ||
9 | int null_call(cycles_t *timestamp); | ||
10 | |||
11 | static 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 | |||
6 | typedef unsigned long cycles_t; | ||
7 | |||
8 | #define CYCLES_FMT "lu" | ||
9 | |||
10 | static 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 | |||
10 | static __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 | |||
23 | typedef unsigned long long cycles_t; | ||
24 | |||
25 | static 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 | */ | ||
7 | static inline void cli(void) { | ||
8 | asm volatile("cli": : :"memory"); | ||
9 | } | ||
10 | |||
11 | static 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 | ||
7 | int main(int argc, char** argv) | 7 | int 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 | ||
10 | static void time_null_call(void) | 9 | static 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 | ||
13 | static double cputime() | 14 | |
15 | static 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 | */ | ||
32 | static 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 | ||
23 | static double wctime() | 39 | static 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 | ||
30 | void usage(char *error) { | 47 | static 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 |
39 | static int num[NUMS]; | 98 | static int num[NUMS]; |
40 | static double loop_length = 1.0; | ||
41 | static char* progname; | 99 | static char* progname; |
42 | 100 | ||
43 | static int loop_once(void) | 101 | static int loop_once(void) |
@@ -48,74 +106,40 @@ static int loop_once(void) | |||
48 | return j; | 106 | return j; |
49 | } | 107 | } |
50 | 108 | ||
51 | static int loop_for(double exec_time) | 109 | static 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 | ||
71 | static 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 | |||
83 | static 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 | |||
104 | static 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 | ||
111 | static void debug_delay_loop(void) | 135 | static 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 | ||
129 | static int job(double exec_time) | 153 | static 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 | ||
138 | int main(int argc, char** argv) | 166 | int 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 | |||
4 | obj-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 | |||
13 | ifeq ($(MAKECMDGOALS),) | ||
14 | MAKECMDGOALS += all | ||
15 | endif | ||
16 | |||
17 | ifneq ($(filter-out clean,$(MAKECMDGOALS)),) | ||
18 | |||
19 | # Pull in dependencies. | ||
20 | -include ${obj-all:.o=.d} | ||
21 | |||
22 | endif | ||
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) \ | ||
11 | do { __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 | |||
20 | static inline void barrier(void) | ||
21 | { | ||
22 | mb(); | ||
23 | } | ||
24 | |||
25 | |||
26 | #define cpu_relax() barrier() | ||
27 | |||
28 | static inline int | ||
29 | cmpxchg(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 | |||
42 | typedef 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 | */ | ||
71 | static __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 | |||
85 | static __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 | |||
9 | static inline void barrier(void) | ||
10 | { | ||
11 | __asm__ __volatile__("mfence": : :"memory"); | ||
12 | } | ||
13 | |||
14 | static __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 | */ | ||
22 | static inline void cli(void) { | ||
23 | asm volatile("cli": : :"memory"); | ||
24 | } | ||
25 | |||
26 | static inline void sti(void) { | ||
27 | asm volatile("sti": : :"memory"); | ||
28 | } | ||
29 | |||
30 | typedef 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 | |||
53 | static __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 | */ | ||
68 | static __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 | */ | ||
95 | static 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 | */ | ||
107 | static 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 | */ | ||
119 | static 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 | */ | ||
133 | static 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 | |||
12 | static __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 | |||
26 | typedef unsigned long long cycles_t; | ||
27 | |||
28 | static inline cycles_t get_cycles(void) | ||
29 | { | ||
30 | return native_read_tsc(); | ||
31 | } | ||
32 | #elif defined __i386__ | ||
33 | static inline unsigned long long native_read_tsc(void) { | ||
34 | unsigned long long val; | ||
35 | __asm__ __volatile__("rdtsc" : "=A" (val)); | ||
36 | return val; | ||
37 | } | ||
38 | |||
39 | typedef unsigned long long cycles_t; | ||
40 | |||
41 | #define CYCLES_FMT "llu" | ||
42 | |||
43 | static inline cycles_t get_cycles(void) | ||
44 | { | ||
45 | return native_read_tsc(); | ||
46 | } | ||
47 | #elif defined __sparc__ | ||
48 | |||
49 | #define NPT_BIT 63 | ||
50 | |||
51 | typedef unsigned long cycles_t; | ||
52 | |||
53 | #define CYCLES_FMT "lu" | ||
54 | |||
55 | static 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 @@ | |||
5 | extern "C" { | 5 | extern "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 | ||
18 | typedef int pid_t; /* PID of a task */ | 18 | typedef 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 */ |
65 | int fmlp_down(int od); | 65 | int litmus_lock(int od); |
66 | int fmlp_up(int od); | 66 | int litmus_unlock(int od); |
67 | |||
68 | /* SRP binary semaphore support */ | ||
69 | int srp_down(int od); | ||
70 | int srp_up(int od); | ||
71 | 67 | ||
72 | /* job control*/ | 68 | /* job control*/ |
73 | int get_job_no(unsigned int* job_no); | 69 | int 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 */ | ||
113 | double cputime(void); | ||
114 | |||
115 | /* wall-clock time in seconds */ | ||
116 | double wctime(void); | ||
117 | |||
116 | /* semaphore allocation */ | 118 | /* semaphore allocation */ |
117 | 119 | ||
118 | static inline int open_fmlp_sem(int fd, int name) | 120 | static inline int open_fmlp_sem(int fd, int name) |
@@ -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 | ||
5 | ADIR=/proc/litmus/active_plugin | 5 | ADIR=/proc/litmus/active_plugin |
6 | PDIR=/proc/litmus/plugins/loaded | 6 | PDIR=/proc/litmus/plugins/loaded |
7 | DIALOG=`which dialog` | 7 | DIALOG=`which dialog 2> /dev/null` |
8 | 8 | ||
9 | CHOICE=$1 | 9 | CHOICE=$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` |
@@ -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 */ | ||
7 | double 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 */ | ||
18 | double 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 | ||
10 | struct 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 | ||
44 | int fmlp_down(int od) | 47 | int litmus_lock(int od) |
45 | { | ||
46 | return syscall(__NR_fmlp_down, od); | ||
47 | } | ||
48 | |||
49 | int fmlp_up(int od) | ||
50 | { | ||
51 | return syscall(__NR_fmlp_up, od); | ||
52 | } | ||
53 | |||
54 | int srp_down(int od) | ||
55 | { | 48 | { |
56 | return syscall(__NR_srp_down, od); | 49 | return syscall(__NR_litmus_lock, od); |
57 | } | 50 | } |
58 | 51 | ||
59 | int srp_up(int od) | 52 | int litmus_unlock(int od) |
60 | { | 53 | { |
61 | return syscall(__NR_srp_up, od); | 54 | return syscall(__NR_litmus_unlock, od); |
62 | } | 55 | } |
63 | 56 | ||
64 | int get_job_no(unsigned int *job_no) | 57 | int 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 | |||
57 | TESTCASE(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, | |||
29 | TESTCASE(invalid_od, ALL, | 31 | TESTCASE(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 | |||
9 | TESTCASE(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 | |||
32 | TESTCASE(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 | |||
49 | TESTCASE(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 | |||
81 | TESTCASE(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 | ||