├── .autotools
├── .cproject
├── .gitignore
├── .project
├── .travis.sh
├── .travis.yml
├── AUTHORS
├── COPYING
├── Makefile.am
├── README.rst
├── configure.ac
├── libctx.pc.in
├── m4
└── .keep
└── src
├── Makefile.am
├── benchmark.c
├── ctx.c
├── ctx.h
├── gas-aarch64-aapcs.S
├── gas-arm-aapcs.S
├── gas-mips-o32.S
├── gas-ppc-sysv.S
├── gas-sparc-sysv.S
├── gas-x86_32-sysv.S
├── gas-x86_64-sysv.S
└── test.c
/.autotools:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/.cproject:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 | make
65 |
66 | all
67 | true
68 | true
69 | false
70 |
71 |
72 | make
73 |
74 | am--refresh
75 | true
76 | true
77 | false
78 |
79 |
80 | make
81 |
82 | check
83 | true
84 | true
85 | false
86 |
87 |
88 | make
89 |
90 | clean
91 | true
92 | true
93 | false
94 |
95 |
96 | make
97 |
98 | clean-cscope
99 | true
100 | true
101 | false
102 |
103 |
104 | make
105 |
106 | clean-libtool
107 | true
108 | true
109 | false
110 |
111 |
112 | make
113 |
114 | cscope
115 | true
116 | true
117 | false
118 |
119 |
120 | make
121 |
122 | cscope.files
123 | true
124 | true
125 | false
126 |
127 |
128 | make
129 |
130 | cscopelist
131 | true
132 | true
133 | false
134 |
135 |
136 | make
137 |
138 | ctags
139 | true
140 | true
141 | false
142 |
143 |
144 | make
145 |
146 | dist
147 | true
148 | true
149 | false
150 |
151 |
152 | make
153 |
154 | dist-all
155 | true
156 | true
157 | false
158 |
159 |
160 | make
161 |
162 | dist-bzip2
163 | true
164 | true
165 | false
166 |
167 |
168 | make
169 |
170 | dist-gzip
171 | true
172 | true
173 | false
174 |
175 |
176 | make
177 |
178 | dist-lzip
179 | true
180 | true
181 | false
182 |
183 |
184 | make
185 |
186 | dist-shar
187 | true
188 | true
189 | false
190 |
191 |
192 | make
193 |
194 | dist-tarZ
195 | true
196 | true
197 | false
198 |
199 |
200 | make
201 |
202 | dist-xz
203 | true
204 | true
205 | false
206 |
207 |
208 | make
209 |
210 | dist-zip
211 | true
212 | true
213 | false
214 |
215 |
216 | make
217 |
218 | distcheck
219 | true
220 | true
221 | false
222 |
223 |
224 | make
225 |
226 | distclean
227 | true
228 | true
229 | false
230 |
231 |
232 | make
233 |
234 | distclean-libtool
235 | true
236 | true
237 | false
238 |
239 |
240 | make
241 |
242 | distclean-tags
243 | true
244 | true
245 | false
246 |
247 |
248 | make
249 |
250 | distcleancheck
251 | true
252 | true
253 | false
254 |
255 |
256 | make
257 |
258 | distdir
259 | true
260 | true
261 | false
262 |
263 |
264 | make
265 |
266 | distuninstallcheck
267 | true
268 | true
269 | false
270 |
271 |
272 | make
273 |
274 | dvi
275 | true
276 | true
277 | false
278 |
279 |
280 | make
281 |
282 | html
283 | true
284 | true
285 | false
286 |
287 |
288 | make
289 |
290 | info
291 | true
292 | true
293 | false
294 |
295 |
296 | make
297 |
298 | install
299 | true
300 | true
301 | false
302 |
303 |
304 | make
305 |
306 | install-data
307 | true
308 | true
309 | false
310 |
311 |
312 | make
313 |
314 | install-dvi
315 | true
316 | true
317 | false
318 |
319 |
320 | make
321 |
322 | install-exec
323 | true
324 | true
325 | false
326 |
327 |
328 | make
329 |
330 | install-html
331 | true
332 | true
333 | false
334 |
335 |
336 | make
337 |
338 | install-info
339 | true
340 | true
341 | false
342 |
343 |
344 | make
345 |
346 | install-man
347 | true
348 | true
349 | false
350 |
351 |
352 | make
353 |
354 | install-pdf
355 | true
356 | true
357 | false
358 |
359 |
360 | make
361 |
362 | install-pkgconfigDATA
363 | true
364 | true
365 | false
366 |
367 |
368 | make
369 |
370 | install-ps
371 | true
372 | true
373 | false
374 |
375 |
376 | make
377 |
378 | install-strip
379 | true
380 | true
381 | false
382 |
383 |
384 | make
385 |
386 | installcheck
387 | true
388 | true
389 | false
390 |
391 |
392 | make
393 |
394 | installdirs
395 | true
396 | true
397 | false
398 |
399 |
400 | make
401 |
402 | libctx.pc
403 | true
404 | true
405 | false
406 |
407 |
408 | make
409 |
410 | maintainer-clean
411 | true
412 | true
413 | false
414 |
415 |
416 | make
417 |
418 | Makefile
419 | true
420 | true
421 | false
422 |
423 |
424 | make
425 |
426 | mostlyclean
427 | true
428 | true
429 | false
430 |
431 |
432 | make
433 |
434 | mostlyclean-libtool
435 | true
436 | true
437 | false
438 |
439 |
440 | make
441 |
442 | pdf
443 | true
444 | true
445 | false
446 |
447 |
448 | make
449 |
450 | ps
451 | true
452 | true
453 | false
454 |
455 |
456 | make
457 |
458 | tags
459 | true
460 | true
461 | false
462 |
463 |
464 | make
465 |
466 | uninstall
467 | true
468 | true
469 | false
470 |
471 |
472 | make
473 |
474 | uninstall-pkgconfigDATA
475 | true
476 | true
477 | false
478 |
479 |
480 |
481 |
482 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.la
2 | *.lo
3 | *.log
4 | *.m4
5 | *.o
6 | *.trs
7 | .deps
8 | .libs
9 | Makefile
10 | Makefile.in
11 | aclocal.m4
12 | autom4te.cache
13 | compile
14 | config.guess
15 | config.log
16 | config.status
17 | config.sub
18 | configure
19 | depcomp
20 | install-sh
21 | libctx.pc
22 | libtool
23 | ltmain.sh
24 | missing
25 | src/benchmark
26 | src/test
27 | test-driver
28 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | libctx
4 |
5 |
6 |
7 |
8 |
9 | org.eclipse.cdt.autotools.core.genmakebuilderV2
10 |
11 |
12 |
13 |
14 | org.eclipse.cdt.managedbuilder.core.genmakebuilder
15 | clean,full,incremental,
16 |
17 |
18 |
19 |
20 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder
21 | full,incremental,
22 |
23 |
24 |
25 |
26 |
27 | org.eclipse.cdt.core.cnature
28 | org.eclipse.cdt.managedbuilder.core.managedBuildNature
29 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature
30 | org.eclipse.cdt.autotools.core.autotoolsNatureV2
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.travis.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash -ex
2 |
3 | CORE="automake autoconf libtool make curl $CC"
4 |
5 | case "$1" in
6 | multiarch/debian-*|multiarch/ubuntu-*)
7 | apt-get update
8 | apt-get -y install $CORE build-essential
9 | ;;
10 |
11 | multiarch/fedora:*)
12 | [ "$CC" == "clang" ] && rt=compiler-rt
13 | dnf -y install $CORE $rt
14 | ;;
15 |
16 | multiarch/centos:*)
17 | yum -y install $CORE gcc
18 | ;;
19 | esac
20 |
21 | autoreconf -if
22 |
23 | if ! CFLAGS=-coverage LDFLAGS=-lgcov ./configure --prefix=/usr; then
24 | cat ./config.log
25 | exit 1
26 | fi
27 |
28 | make -j8 -k check V=1 TESTS=
29 |
30 | if ! make -j8 check; then
31 | cat ./test-suite.log
32 | exit 1
33 | fi
34 |
35 | bash <(curl -s https://codecov.io/bash)
36 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 |
3 | language: c
4 |
5 | services:
6 | - docker
7 |
8 | #osx_image: xcode8
9 | #os:
10 | # - linux
11 | # - osx
12 |
13 | compiler:
14 | - clang
15 | - gcc
16 |
17 | env:
18 | - DISTRO=multiarch/fedora:25-aarch64
19 | - DISTRO=multiarch/fedora:25-armhfp
20 | - DISTRO=multiarch/fedora:25-x86_64
21 |
22 | - DISTRO=multiarch/centos:7-aarch64-iso
23 | - DISTRO=multiarch/centos:7-armhfp-iso
24 | - DISTRO=multiarch/centos:7-i386-iso
25 | - DISTRO=multiarch/centos:7-x86_64-iso
26 |
27 | - DISTRO=multiarch/debian-debootstrap:amd64-stretch
28 | - DISTRO=multiarch/debian-debootstrap:arm64-stretch
29 | - DISTRO=multiarch/debian-debootstrap:armel-stretch
30 | - DISTRO=multiarch/debian-debootstrap:armhf-stretch
31 | - DISTRO=multiarch/debian-debootstrap:i386-stretch
32 | - DISTRO=multiarch/debian-debootstrap:mips-stretch
33 | - DISTRO=multiarch/debian-debootstrap:mipsel-stretch
34 | - DISTRO=multiarch/debian-debootstrap:powerpc-stretch
35 | - DISTRO=multiarch/debian-debootstrap:ppc64el-stretch
36 | - DISTRO=multiarch/debian-debootstrap:s390x-stretch
37 |
38 | - DISTRO=multiarch/debian-debootstrap:amd64-jessie
39 | - DISTRO=multiarch/debian-debootstrap:arm64-jessie
40 | - DISTRO=multiarch/debian-debootstrap:armel-jessie
41 | - DISTRO=multiarch/debian-debootstrap:armhf-jessie
42 | - DISTRO=multiarch/debian-debootstrap:i386-jessie
43 | - DISTRO=multiarch/debian-debootstrap:mips-jessie
44 | - DISTRO=multiarch/debian-debootstrap:mipsel-jessie
45 | - DISTRO=multiarch/debian-debootstrap:powerpc-jessie
46 | - DISTRO=multiarch/debian-debootstrap:ppc64el-jessie
47 | - DISTRO=multiarch/debian-debootstrap:s390x-jessie
48 |
49 | - DISTRO=multiarch/ubuntu-debootstrap:amd64-yakkety
50 | - DISTRO=multiarch/ubuntu-debootstrap:arm64-yakkety
51 | - DISTRO=multiarch/ubuntu-debootstrap:armhf-yakkety
52 | - DISTRO=multiarch/ubuntu-debootstrap:i386-yakkety
53 | - DISTRO=multiarch/ubuntu-debootstrap:powerpc-yakkety
54 | - DISTRO=multiarch/ubuntu-debootstrap:ppc64el-yakkety
55 |
56 | - DISTRO=multiarch/ubuntu-debootstrap:amd64-xenial
57 | - DISTRO=multiarch/ubuntu-debootstrap:arm64-xenial
58 | - DISTRO=multiarch/ubuntu-debootstrap:armhf-xenial
59 | - DISTRO=multiarch/ubuntu-debootstrap:i386-xenial
60 | - DISTRO=multiarch/ubuntu-debootstrap:powerpc-xenial
61 | - DISTRO=multiarch/ubuntu-debootstrap:ppc64el-xenial
62 |
63 | script:
64 | - docker run --rm --privileged multiarch/qemu-user-static:register --reset
65 | - docker run -v `pwd`:/tmp/test -w /tmp/test -e CC=$CC $DISTRO ./.travis.sh $DISTRO
66 |
--------------------------------------------------------------------------------
/AUTHORS:
--------------------------------------------------------------------------------
1 | Nathaniel McCallum
2 | Oliver Kowalke
3 | Martin Husemann
4 |
--------------------------------------------------------------------------------
/COPYING:
--------------------------------------------------------------------------------
1 | Boost Software License - Version 1.0 - August 17th, 2003
2 |
3 | Permission is hereby granted, free of charge, to any person or organization
4 | obtaining a copy of the software and accompanying documentation covered by
5 | this license (the "Software") to use, reproduce, display, distribute,
6 | execute, and transmit the Software, and to prepare derivative works of the
7 | Software, and to permit third-parties to whom the Software is furnished to
8 | do so, all subject to the following:
9 |
10 | The copyright notices in the Software and this entire statement, including
11 | the above license grant, this restriction and the following disclaimer,
12 | must be included in all copies of the Software, in whole or in part, and
13 | all derivative works of the Software, unless such copies or derivative
14 | works are solely in the form of machine-executable object code generated by
15 | a source language processor.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23 | DEALINGS IN THE SOFTWARE.
--------------------------------------------------------------------------------
/Makefile.am:
--------------------------------------------------------------------------------
1 | ACLOCAL_AMFLAGS = -I m4
2 | SUBDIRS = . src
3 |
4 | pkgconfigdir = $(libdir)/pkgconfig
5 | pkgconfig_DATA = libctx.pc
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | +--------+------------+----------------------------------------------+
2 | | Name | License | Description |
3 | +========+============+==============================================+
4 | | libctx | Boost v1.0 | A cooperative multitasking library for C/C++ |
5 | +--------+------------+----------------------------------------------+
6 |
7 | About
8 | =======
9 | libctx began life as a port of Boost::Context to C and ended up a substantial
10 | rewrite for speed (extremely minor), flexibility and new architecture support.
11 | This library enables functions like co-routines, exceptions or other neat
12 | tricks in C. libctx attempts (and succeeds!) at being small and self-
13 | contained. While the features found here are fun and interesting, some care
14 | should be taken in their use since, without careful planning, things can go
15 | downhill quickly.
16 |
17 | Testing
18 | =======
19 | libctx has been tested in the following configurations:
20 |
21 | +----------------+-------+-------+-------+-------+--------+--------+
22 | | | x86 | arm | sparc | ppc | mips | mipsel |
23 | +================+=======+=======+=======+=======+========+========+
24 | | **Debian** | 32/64 | 32/64 | 32/64 | 32/64 | 32 | 32 |
25 | +----------------+-------+-------+-------+-------+--------+--------+
26 | | **Fedora** | 32/64 | 32/64 | | | | |
27 | +----------------+-------+-------+-------+-------+--------+--------+
28 | | **FreeBSD** | 32/64 | | | | | |
29 | +----------------+-------+-------+-------+-------+--------+--------+
30 | | **NetBSD** | 32/64 | | | | | |
31 | +----------------+-------+-------+-------+-------+--------+--------+
32 | | **OpenBSD** | 32/64 | | | | | |
33 | +----------------+-------+-------+-------+-------+--------+--------+
34 | | **Apple OS X** | 32/64 | | | | | |
35 | +----------------+-------+-------+-------+-------+--------+--------+
36 | | **Solaris** | 32/64 | | | | | |
37 | +----------------+-------+-------+-------+-------+--------+--------+
38 |
39 | Problem Description
40 | ===================
41 | There have long been functions for jumping around code in C. Several have seen
42 | wide adoption, but suffer from inconsistent implementations or other
43 | restrictions.
44 |
45 | setjmp
46 | ------
47 | The earliest are setjmp()/longjmp(). These functions are available on pretty
48 | much any UNIX/Linux system, but come with a number of problems. Most severely,
49 | because you cannot execute functions on an independent stacks, you can only
50 | jump in the direction of stack unwinding. Secondarily, implementations provide
51 | inconsistent support for extended CPU state saving. One feature that setjmp
52 | has that others don't is support for saving/restoring signal mask state. While
53 | this sounds neat at first, mixing signals and cooperative multitasking is bad
54 | mojo. Just don't do it (there is a reason no one else implements this).
55 |
56 | ucontext
57 | --------
58 | Next came an attempt at UNIX standardization via ucontext. This approach
59 | provides a mechanism for independent stacks, but still suffers from
60 | inconsistent implementations. Some implementations of ucontext also depend on
61 | memory allocation during state save, decreasing performance.
62 |
63 | Boost::Context
64 | --------------
65 | Of the many other attempts not worth mentioning, Boost::Context stands out. It
66 | is mature, consistent and widely-deployed. Its main problem is that it is
67 | written in C++ and I wished to use it in C applications. If you are already
68 | using Boost, you probably want to use Boost::Context. However, if you don't
69 | want to add a dependency on C++, or you don't plan on using Boost, you might
70 | find libctx useful. One other reason you may want to use libctx instead of
71 | Boost::Context is that libctx supports AARCH64 (a.k.a. ARMv8).
72 |
73 | Windows Support
74 | ===============
75 | I don't currently plan on supporting Windows. Not that I'm against
76 | it, I just don't have systems to test it on. Boost::Context already
77 | provides Windows support. Feel free to use it. If you'd like to use
78 | libctx on Windows, it should be a fairly straightforward port from
79 | Boost::Context. I'd be happy to merge any such patches.
80 |
--------------------------------------------------------------------------------
/configure.ac:
--------------------------------------------------------------------------------
1 | AC_PREREQ(2.60)
2 | AC_INIT([libctx], [0.1], [nathaniel@themccallums.org],
3 | [libctx], [http://www.github.com/npmccallum/libctx])
4 | AC_CONFIG_AUX_DIR([build-aux])
5 | AC_CONFIG_MACRO_DIR([m4])
6 | AC_PREFIX_DEFAULT([/usr])
7 | AC_USE_SYSTEM_EXTENSIONS
8 | AC_CANONICAL_SYSTEM
9 | AC_SYS_LARGEFILE
10 | AC_PROG_CC_STDC
11 | AC_PROG_LIBTOOL
12 |
13 | AM_INIT_AUTOMAKE([check-news foreign 1.11 -Wall -Wno-portability silent-rules tar-pax no-dist-gzip dist-xz subdir-objects])
14 | AM_SILENT_RULES([yes])
15 | AM_PROG_CC_C_O
16 | AM_PROG_AS
17 |
18 | LT_INIT([disable-static pic-only])
19 |
20 | dnl Check for pointer size
21 | AC_CHECK_SIZEOF([void *])
22 | case $ac_cv_sizeof_void_p in
23 | 4) BITS=32; AC_DEFINE([CTX_32BIT]);;
24 | 8) BITS=64; AC_DEFINE([CTX_64BIT]);;
25 | *) AC_MSG_ERROR([invalid size ($ac_cv_sizeof_void_p)]);;
26 | esac
27 |
28 | dnl Check for architecture
29 | AC_MSG_CHECKING([compatibility ($target_cpu)])
30 | case $target_cpu in
31 | arm*) IMPLEMENTATION=gas-arm-aapcs.lo;;
32 | aarch64) IMPLEMENTATION=gas-aarch64-aapcs.lo;;
33 | mips*) IMPLEMENTATION=gas-mips-o32.lo;;
34 | powerpc*) IMPLEMENTATION=gas-ppc-sysv.lo;;
35 | sparc*) IMPLEMENTATION=gas-sparc-sysv.lo;;
36 | i?86|x86_64|amd64) IMPLEMENTATION=gas-x86_$BITS-sysv.lo;;
37 | *) AC_MSG_ERROR([not found]);;
38 | esac
39 | AC_MSG_RESULT([$IMPLEMENTATION])
40 | AC_SUBST(IMPLEMENTATION)
41 |
42 | AC_CONFIG_FILES(Makefile libctx.pc src/Makefile)
43 | AC_OUTPUT
44 | AC_MSG_RESULT([
45 | $PACKAGE $VERSION
46 | ========
47 |
48 | prefix: ${prefix}
49 | libdir: ${libdir}
50 | includedir: ${includedir}
51 | localstatedir: ${localstatedir}
52 |
53 | compiler: ${CC}
54 | cflags: ${CFLAGS}
55 | ldflags: ${LDFLAGS}
56 |
57 | host: ${host}
58 | build: ${build}
59 | target: ${target}
60 | ])
--------------------------------------------------------------------------------
/libctx.pc.in:
--------------------------------------------------------------------------------
1 | prefix=@prefix@
2 | exec_prefix=@exec_prefix@
3 | libdir=@libdir@
4 | includedir=@includedir@
5 |
6 | Name: libctx
7 | Description: A cooperative multitasking library for C/C++
8 | Version: @VERSION@
9 | Libs: -L${libdir} -lctx
10 | Libs.private:
11 | Cflags: -I${includedir}
--------------------------------------------------------------------------------
/m4/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/npmccallum/libctx/2487901730ed78d762163f55e609bff2c141131f/m4/.keep
--------------------------------------------------------------------------------
/src/Makefile.am:
--------------------------------------------------------------------------------
1 | LDADD = libctx.la
2 |
3 | AM_CFLAGS = \
4 | -Wall \
5 | -Wmissing-declarations \
6 | -Wmissing-prototypes \
7 | -Wnested-externs \
8 | -Wpointer-arith \
9 | -Wpointer-arith \
10 | -Wsign-compare \
11 | -Wchar-subscripts \
12 | -Wstrict-prototypes \
13 | -Wformat-security \
14 | -ffunction-sections \
15 | -fdata-sections
16 |
17 | include_HEADERS = ctx.h
18 | lib_LTLIBRARIES = libctx.la
19 | check_PROGRAMS = test benchmark
20 | TESTS = $(check_PROGRAMS)
21 |
22 | libctx_la_SOURCES = ctx.c
23 | libctx_la_LIBADD = $(IMPLEMENTATION)
24 | libctx_la_DEPENDENCIES = $(IMPLEMENTATION)
25 | libctx_la_LDFLAGS = $(AM_LDFLAGS) -version-info 0:0:0 \
26 | -export-symbols-regex '^ctx_'
27 | EXTRA_libctx_la_SOURCES = \
28 | gas-arm-aapcs.S \
29 | gas-mips-o32.S \
30 | gas-ppc-sysv.S \
31 | gas-sparc-sysv.S \
32 | gas-x86_32-sysv.S \
33 | gas-x86_64-sysv.S
34 |
--------------------------------------------------------------------------------
/src/benchmark.c:
--------------------------------------------------------------------------------
1 | /*
2 | * libctx - A cooperative multitasking library for C/C++
3 | *
4 | * Copyright 2013 Nathaniel McCallum
5 | *
6 | * Distributed under the Boost Software License, Version 1.0.
7 | */
8 |
9 | #include
10 |
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 |
17 | #define ITERATIONS 25000
18 |
19 | #define RFMT "%8s: %d.%06u\n"
20 | #define FMT "%s-" RFMT
21 | #define DIFF(one, two) ((one > two) ? (one - two) : (two - one))
22 | #define SECONDS(stv, etv) ((unsigned int) (etv.tv_sec - stv.tv_sec - \
23 | ((stv.tv_usec > etv.tv_usec) ? 1 : 0)))
24 | #define USECONDS(stv, etv) ((unsigned int) DIFF(etv.tv_usec, stv.tv_usec))
25 | #define TIME(stv, etv) SECONDS(stv, etv), USECONDS(stv, etv)
26 |
27 | struct bundle {
28 | ctx_state state;
29 | ctx_extra extra;
30 | };
31 |
32 | static volatile uintptr_t j;
33 |
34 | static int
35 | test_return(void *param)
36 | {
37 | ++j;
38 | return 0;
39 | }
40 |
41 | static int
42 | test_noext(void *param)
43 | {
44 | ctx_state state;
45 |
46 | while (1) {
47 | ++j;
48 | if (ctx_mark(&state, NULL, ¶m) == 0)
49 | ctx_jump(param, NULL, &state);
50 | }
51 |
52 | return 0;
53 | }
54 |
55 | static int
56 | test_ext(void *param)
57 | {
58 | struct bundle bundle;
59 |
60 | while (1) {
61 | ++j;
62 | if (ctx_mark(&bundle.state, &bundle.extra, ¶m) == 0)
63 | ctx_jump(&((struct bundle *) param)->state,
64 | &((struct bundle *) param)->extra, &bundle);
65 | }
66 |
67 | return 0;
68 | }
69 |
70 | int
71 | main(int argc, char **argv)
72 | {
73 | struct timeval stv, etv;
74 | struct bundle bundle, *rbundle;
75 | ctx_state *rstate;
76 | ctx_stack stk;
77 |
78 | stk.size = 1;
79 | assert(ctx_new(&stk) == 0);
80 |
81 | gettimeofday(&stv, NULL);
82 | for (j = 0; j < ITERATIONS; )
83 | test_return(NULL);
84 | gettimeofday(&etv, NULL);
85 | printf(RFMT, "return", TIME(stv, etv));
86 |
87 | gettimeofday(&stv, NULL);
88 | for (j = 0; ctx_mark(&bundle.state, NULL, &rstate) < ITERATIONS; ) {
89 | if (j == 0)
90 | ctx_call(&bundle.state, stk, test_noext);
91 | else
92 | ctx_jump(rstate, NULL, &bundle.state);
93 | }
94 | gettimeofday(&etv, NULL);
95 | printf(RFMT, "noexts", TIME(stv, etv));
96 |
97 | gettimeofday(&stv, NULL);
98 | for (j = 0; j < ITERATIONS; ) {
99 | if (ctx_mark(&bundle.state, NULL, &rstate) == 0) {
100 | if (j == 0)
101 | ctx_call(&bundle.state, stk, test_noext);
102 | else
103 | ctx_jump(rstate, NULL, &bundle.state);
104 | }
105 | }
106 | gettimeofday(&etv, NULL);
107 | printf(RFMT, "noextd", TIME(stv, etv));
108 |
109 | gettimeofday(&stv, NULL);
110 | for (j = 0; ctx_mark(&bundle.state, &bundle.extra, &rbundle) < ITERATIONS; ) {
111 | if (j == 0)
112 | ctx_call(&bundle, stk, test_ext);
113 | else
114 | ctx_jump(&rbundle->state, &rbundle->extra, &bundle);
115 | }
116 | gettimeofday(&etv, NULL);
117 | printf(RFMT, "exts", TIME(stv, etv));
118 |
119 | gettimeofday(&stv, NULL);
120 | for (j = 0; j < ITERATIONS; ) {
121 | if (ctx_mark(&bundle.state, &bundle.extra, &rbundle) == 0) {
122 | if (j == 0)
123 | ctx_call(&bundle, stk, test_ext);
124 | else
125 | ctx_jump(&rbundle->state, &rbundle->extra, &bundle);
126 | }
127 | }
128 | gettimeofday(&etv, NULL);
129 | printf(RFMT, "extd", TIME(stv, etv));
130 |
131 | ctx_free(stk);
132 | return 0;
133 | }
134 |
--------------------------------------------------------------------------------
/src/ctx.c:
--------------------------------------------------------------------------------
1 | /*
2 | * libctx - A cooperative multitasking library for C/C++
3 | *
4 | * Copyright 2013 Nathaniel McCallum
5 | * Portions Copyright 2009 Oliver Kowalke
6 | *
7 | * Distributed under the Boost Software License, Version 1.0.
8 | */
9 |
10 | #include "ctx.h"
11 |
12 | #include
13 | #include
14 | #include
15 |
16 | #include
17 | #include
18 | #include
19 | #include
20 |
21 | #define PROT_RW (PROT_READ | PROT_WRITE)
22 | #if defined(MAP_ANON)
23 | # define FLAGS (MAP_PRIVATE | MAP_ANON)
24 | #elif defined (MAP_ANONYMOUS)
25 | # define FLAGS (MAP_PRIVATE | MAP_ANONYMOUS)
26 | #else
27 | # define FLAGS (MAP_PRIVATE)
28 | #endif
29 |
30 | #if !defined(MINSIGSTKSZ)
31 | # define MINSIGSTKSZ (8 * 1024)
32 | #endif
33 |
34 | #if !defined(SIGSTKSZ)
35 | # define SIGSTKSZ (32 * 1024)
36 | #endif
37 |
38 | static inline long
39 | pagesize(void)
40 | {
41 | static long ps = 0;
42 |
43 | if (ps == 0)
44 | assert((ps = sysconf(_SC_PAGESIZE)) > 0);
45 |
46 | return ps;
47 | }
48 |
49 | static inline struct rlimit
50 | limit(void)
51 | {
52 | static struct rlimit limit = { 0, 0 };
53 |
54 | if (limit.rlim_cur == 0 && limit.rlim_max == 0)
55 | assert(getrlimit(RLIMIT_STACK, &limit) == 0);
56 |
57 | return limit;
58 | }
59 |
60 | int
61 | ctx_new(ctx_stack *stack)
62 | {
63 | int err, fd = -1;
64 | unsigned char *tmp;
65 |
66 | if (stack == NULL)
67 | return EINVAL;
68 |
69 | if (stack->size == 0)
70 | stack->size = SIGSTKSZ;
71 |
72 | if (stack->size < MINSIGSTKSZ)
73 | stack->size = MINSIGSTKSZ;
74 |
75 | stack->size += pagesize() * 2 - 1; /* Add a guard page. */
76 | stack->size = stack->size / pagesize() * pagesize(); /* Round off. */
77 |
78 | if (limit().rlim_max != RLIM_INFINITY &&
79 | limit().rlim_max < (rlim_t) stack->size)
80 | return E2BIG;
81 |
82 | #if !defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
83 | fd = open("/dev/zero", O_RDONLY);
84 | if (fd < 0)
85 | return errno;
86 | #endif
87 |
88 | tmp = mmap(NULL, stack->size, PROT_RW, FLAGS, fd, 0);
89 | err = errno;
90 | if (fd >= 0)
91 | close(fd);
92 | if (tmp == NULL)
93 | return err;
94 |
95 | if (mprotect(tmp, pagesize(), PROT_NONE) != 0) {
96 | munmap(tmp, stack->size);
97 | return errno;
98 | }
99 |
100 | stack->stack = tmp + stack->size;
101 | stack->size -= pagesize();
102 | return 0;
103 | }
104 |
105 | void
106 | ctx_free(ctx_stack stack)
107 | {
108 | if (stack.stack == NULL || stack.size == 0)
109 | return;
110 |
111 | stack.size += pagesize();
112 | munmap(((unsigned char*) stack.stack) - stack.size, stack.size);
113 | }
114 |
--------------------------------------------------------------------------------
/src/ctx.h:
--------------------------------------------------------------------------------
1 | /*
2 | * libctx - A cooperative multitasking library for C/C++
3 | *
4 | * Copyright 2013 Nathaniel McCallum
5 | * Portions Copyright 2009 Oliver Kowalke
6 | *
7 | * Distributed under the Boost Software License, Version 1.0.
8 | */
9 |
10 | #pragma once
11 |
12 | #include
13 | #include
14 | #include
15 |
16 | #ifdef _MSC_VER
17 | #define __CTX_ALIGN(x) __declspec(align(x))
18 | #define __CTX_NORETURN __declspec(noreturn)
19 | #else
20 | #define __CTX_ALIGN(x) __attribute__((aligned(x)))
21 | #define __CTX_NORETURN __attribute__((noreturn))
22 | #endif
23 |
24 | typedef struct ctx_stack ctx_stack;
25 | typedef struct ctx_state ctx_state;
26 | typedef struct ctx_extra ctx_extra;
27 |
28 | #pragma pack(0)
29 | #if defined(__amd64__) || defined(__amd64) || \
30 | defined(__x86_64__) || defined(__x86_64) || \
31 | defined(_M_X64) || defined(_M_AMD64)
32 | struct ctx_state {
33 | uintptr_t __opaque[10];
34 | };
35 |
36 | struct ctx_extra {
37 | uint8_t __opaque[512];
38 | } __CTX_ALIGN(16);
39 |
40 | #elif defined(i386) || defined(__i386) || defined(__i386__) || \
41 | defined(__i486__) || defined(__i586__) || defined(__i686__) || \
42 | defined(__IA32__) || defined(_M_IX86) || defined(__X86__) || \
43 | defined(_X86_) || defined(__THW_INTEL__) || defined(__I86__) || \
44 | defined(__INTEL__)
45 | struct ctx_state {
46 | uintptr_t __opaque[8];
47 | };
48 |
49 | struct ctx_extra {
50 | uint8_t __opaque[512];
51 | } __CTX_ALIGN(16);
52 |
53 | #elif defined(__arm__) || defined(__thumb__) || defined(__TARGET_ARCH_ARM) || \
54 | defined(__TARGET_ARCH_THUMB) || defined(_ARM) || defined(_M_ARM) || \
55 | defined(_M_ARMT)
56 | struct ctx_state {
57 | uintptr_t __opaque[12];
58 | };
59 |
60 | struct ctx_extra {
61 | uintptr_t __opaque[16];
62 | };
63 |
64 | #elif defined(__aarch64__) || defined(aarch64) || defined(__aarch64) || \
65 | defined (__AARCH64__)
66 | struct ctx_state {
67 | uintptr_t __opaque[16];
68 | };
69 |
70 | struct ctx_extra {
71 | uintptr_t __opaque[8];
72 | };
73 |
74 | #elif defined(__mips__) || defined(mips) || defined(__mips) || defined(__MIPS__)
75 | struct ctx_state {
76 | uintptr_t __opaque[13];
77 | };
78 |
79 | struct ctx_extra {
80 | uintptr_t __opaque[12];
81 | };
82 |
83 | #elif defined(__powerpc) || defined(__powerpc__) || defined(__POWERPC__) || \
84 | defined(__ppc__) || defined(_M_PPC) || defined(_ARCH_PPC)
85 | struct ctx_state {
86 | uintptr_t __opaque[24];
87 | };
88 |
89 | struct ctx_extra {
90 | uint64_t __opaque[19];
91 | };
92 |
93 | #elif defined(__sparc__) || defined(__sparc) || defined(sparc)
94 | struct ctx_state {
95 | uintptr_t __opaque[25];
96 | };
97 |
98 | # if defined(__sparc64__) || defined(_LP64) || defined(__LP64__)
99 | struct ctx_extra {
100 | uintptr_t __opaque[34];
101 | } __CTX_ALIGN(64);
102 | # else
103 | struct ctx_extra {
104 | uintptr_t __opaque[17];
105 | } __CTX_ALIGN(8);
106 | # endif
107 |
108 | #else
109 | #error Architecture not supported!
110 | #endif
111 | #pragma pack()
112 | #undef __CTX_ALIGN
113 |
114 | struct ctx_stack {
115 | void *stack;
116 | size_t size;
117 | };
118 |
119 | /* Allocate a new stack with guard page.
120 | *
121 | * The desired size is specified in the ctx_stack.size field. If
122 | * ctx_stack.size == 0, a default stack size is used. This stack size should
123 | * be estimated to be sufficient for "small" functions. If ctx_stack.size is
124 | * less than an internal minimum stack size, it will be silently upgraded. This
125 | * minimum stack size should be understood to be sufficient for "extra small"
126 | * functions.
127 | *
128 | * Returns 0 on success and errno on error.
129 | *
130 | * NOTE: You do not have to use this function. If you'd prefer to write your
131 | * own stack allocator, you are welcome to.
132 | */
133 | int
134 | ctx_new(ctx_stack *stack);
135 |
136 | /* Free a stack allocated by ctx_new(). */
137 | void
138 | ctx_free(ctx_stack stack);
139 |
140 | /* Call a function on a new stack.
141 | *
142 | * The function specified will be called with the given parameter and will
143 | * execute on the given stack. Once a set of functions are executing in
144 | * independent stacks, you can safely jump between them via ctx_mark() and
145 | * ctx_jump().
146 | *
147 | * If the executed function returns, the return value will be passed to _exit()
148 | * and the process will terminate.
149 | *
150 | * This function does not return.
151 | */
152 | void __CTX_NORETURN
153 | ctx_call(void *param, ctx_stack stack, int (*func)(void *param));
154 | #define ctx_call(p, s, f) ctx_call(p, s, (int (*)(void *)) f)
155 |
156 | /* Mark a point for a later jump via ctx_jump().
157 | *
158 | * Calling this function stores the current processor state in state. If extra
159 | * is not NULL, extended processor state (including floating point) will be
160 | * stored. Once this state is obtained, it may be jumped to via ctx_jump().
161 | * This state is reentrant (if your code is!), so you may call ctx_jump()
162 | * multiple times on a single saved state.
163 | *
164 | * If param is not NULL, it will contain the param argument from a ctx_jump()
165 | * invocation. On the first return (i.e. before any calls to ctx_jump()), param
166 | * will be unmodified.
167 | *
168 | * This function returns the number of times ctx_jump() has been called on the
169 | * processor state.
170 | */
171 | size_t
172 | ctx_mark(ctx_state *state, ctx_extra *extra, void **param);
173 | #define ctx_mark(s, f, p) ctx_mark(s, f, (void **) p)
174 |
175 | /* Jump to a previously saved state.
176 | *
177 | * If extra is not NULL, extended processor state (including floating point)
178 | * will be restored as well. If the param argument of ctx_mark() is not NULL,
179 | * the param argument to ctx_jump() will be stored in the aforementioned
180 | * pointer. Execution will resume as if ctx_mark() returned normally except the
181 | * return value will be incremented.
182 | *
183 | * This function does not return.
184 | */
185 | void __CTX_NORETURN
186 | ctx_jump(ctx_state *state, ctx_extra *extra, void *param);
187 |
188 | #undef __CTX_NORETURN
189 |
--------------------------------------------------------------------------------
/src/gas-aarch64-aapcs.S:
--------------------------------------------------------------------------------
1 | //
2 | // libctx - A cooperative multitasking library for C/C++
3 | //
4 | // Copyright 2013 Nathaniel McCallum
5 | // Portions Copyright 2009 Oliver Kowalke
6 | //
7 | // Distributed under the Boost Software License, Version 1.0.
8 | //
9 |
10 | // ---------------------------------------------------------
11 | // | ctx_state |
12 | // ---------------------------------------------------------
13 | // | 0x00 | 0x08 | 0x10 | 0x18 | 0x20 | 0x28 | 0x30 | 0x38 |
14 | // ---------------------------------------------------------
15 | // | x18 | x19 | x20 | x21 | x22 | x23 | x24 | x25 |
16 | // ---------------------------------------------------------
17 | // | 0x40 | 0x48 | 0x50 | 0x58 | 0x60 | 0x68 | 0x70 | 0x78 |
18 | // ---------------------------------------------------------
19 | // | x26 | x27 | x28 | x29 | x30 | sp | cnt | prm |
20 | // ---------------------------------------------------------
21 | //
22 | // ---------------------------------------------------------
23 | // | ctx_extra |
24 | // ---------------------------------------------------------
25 | // | 0x00 | 0x04 | 0x08 | 0x0c | 0x10 | 0x14 | 0x18 | 0x1c |
26 | // ---------------------------------------------------------
27 | // | d8 | d9 | d10 | d11 | d12 | d13 | d14 | d15 |
28 | // ---------------------------------------------------------
29 |
30 | #if defined(__APPLE__)
31 | # define NAME(name) _ ## name
32 | # define TYPE(name)
33 | # define SIZE(name)
34 | # define EXIT EXIT
35 | #else
36 | # define NAME(name) name
37 | # define TYPE(name) .type name, %function
38 | # define SIZE(name) .size NAME(name), .-NAME(name)
39 | # define EXIT exit
40 | #endif
41 |
42 | // void __CTX_NORETURN
43 | // ctx_call(void *param, ctx_stack stack, int (*func)(void *param));
44 | .text
45 | .globl NAME(ctx_call)
46 | TYPE(ctx_call)
47 | .align 2
48 | NAME(ctx_call):
49 | bic sp, x1, #15 // Set the new, aligned stack.
50 | blr x3 // Call the function.
51 | b EXIT // Exit (argument implicit)
52 | SIZE(ctx_call)
53 |
54 | // size_t
55 | // ctx_mark(ctx_state *state, ctx_extra *extra, void **param);
56 | .text
57 | .globl NAME(ctx_mark)
58 | TYPE(ctx_mark)
59 | .align 2
60 | NAME(ctx_mark):
61 | cbz x1, noextra0 // Is extra NULL?
62 | stp d8, d9, [x1, 0x00] // Save FP registers.
63 | stp d10, d11, [x1, 0x10] // Save FP registers.
64 | stp d12, d13, [x1, 0x20] // Save FP registers.
65 | stp d14, d15, [x1, 0x30] // Save FP registers.
66 |
67 | noextra0:
68 | mov x4, sp // Get SP for later storage.
69 | mov x1, x0 // Move state to a free register.
70 | mov x0, #0 // Set cnt (x1) = 0 / return value.
71 | stp x18, x19, [x1, 0x00] // Save registers.
72 | stp x20, x21, [x1, 0x10] // Save registers.
73 | stp x22, x23, [x1, 0x20] // Save registers.
74 | stp x24, x25, [x1, 0x30] // Save registers.
75 | stp x26, x27, [x1, 0x40] // Save registers.
76 | stp x28, x29, [x1, 0x50] // Save registers.
77 | stp x30, x4, [x1, 0x60] // Save registers.
78 | stp x0, x2, [x1, 0x70] // Save cnt and param.
79 |
80 | ret // Return 0.
81 | SIZE(ctx_mark)
82 |
83 | // void __CTX_NORETURN
84 | // ctx_jump(ctx_state *state, ctx_extra *extra, void *param);
85 | .text
86 | .globl NAME(ctx_jump)
87 | TYPE(ctx_jump)
88 | .align 2
89 | NAME(ctx_jump):
90 | cbz x1, noextra1 // Is extra NULL?
91 | ldp d8, d9, [x1, 0x00] // Load FP registers.
92 | ldp d10, d11, [x1, 0x10] // Load FP registers.
93 | ldp d12, d13, [x1, 0x20] // Load FP registers.
94 | ldp d14, d15, [x1, 0x30] // Load FP registers.
95 |
96 | noextra1:
97 | mov x1, x0 // Move state to a free register.
98 | ldp x18, x19, [x1, 0x00] // Load registers.
99 | ldp x20, x21, [x1, 0x10] // Load registers.
100 | ldp x22, x23, [x1, 0x20] // Load registers.
101 | ldp x24, x25, [x1, 0x30] // Load registers.
102 | ldp x26, x27, [x1, 0x40] // Load registers.
103 | ldp x28, x29, [x1, 0x50] // Load registers.
104 | ldp x30, x4, [x1, 0x60] // Load registers.
105 | ldp x0, x3, [x1, 0x70] // Load cnt and param (cnt is returned).
106 | add x0, x0, #1 // Increment cnt.
107 | str x0, [x1, 0x70] // Store cnt.
108 | mov sp, x4 // Set the stack pointer.
109 |
110 | cbz x3, noparam // Is param NULL?
111 | str x2, [x3] // Save the param.
112 |
113 | noparam:
114 | ret // Return cnt (implicit).
115 | SIZE(ctx_jump)
116 |
--------------------------------------------------------------------------------
/src/gas-arm-aapcs.S:
--------------------------------------------------------------------------------
1 | @
2 | @ libctx - A cooperative multitasking library for C/C++
3 | @
4 | @ Copyright 2013 Nathaniel McCallum
5 | @ Portions Copyright 2009 Oliver Kowalke
6 | @
7 | @ Distributed under the Boost Software License, Version 1.0.
8 | @
9 |
10 | @ ---------------------------------------------------------
11 | @ | ctx_state |
12 | @ ---------------------------------------------------------
13 | @ | 0x00 | 0x04 | 0x08 | 0x0c | 0x10 | 0x14 | 0x18 | 0x1c |
14 | @ ---------------------------------------------------------
15 | @ | cnt | prm | v1 | v2 | v3 | v4 | v5 | v6 |
16 | @ ---------------------------------------------------------
17 | @ | 0x20 | 0x24 | 0x28 | 0x2c | |
18 | @ ---------------------------------------------------------
19 | @ | v7 | v8 | sp | lr | | | | |
20 | @ ---------------------------------------------------------
21 | @
22 | @ ---------------------------------------------------------
23 | @ | ctx_extra |
24 | @ ---------------------------------------------------------
25 | @ | 0x00 | 0x04 | 0x08 | 0x0c | 0x10 | 0x14 | 0x18 | 0x1c |
26 | @ ---------------------------------------------------------
27 | @ | s16 | s17 | s18 | s19 | s20 | s21 | s22 | s23 |
28 | @ ---------------------------------------------------------
29 | @ ---------------------------------------------------------
30 | @ | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c |
31 | @ ---------------------------------------------------------
32 | @ | s24 | s25 | s26 | s27 | s28 | s29 | s30 | s31 |
33 | @ ---------------------------------------------------------
34 |
35 | #if defined(__APPLE__)
36 | # define NAME(name) _ ## name
37 | # define TYPE(name)
38 | # define SIZE(name)
39 | # define EXIT EXIT
40 | #else
41 | # define NAME(name) name
42 | # define TYPE(name) .type name, %function
43 | # define SIZE(name) .size NAME(name), .-NAME(name)
44 | # define EXIT _exit@PLT
45 | #endif
46 |
47 | @ void __CTX_NORETURN
48 | @ ctx_call(void *param, ctx_stack stack, int (*func)(void *param));
49 | .text
50 | .globl NAME(ctx_call)
51 | TYPE(ctx_call)
52 | .align 2
53 | NAME(ctx_call):
54 | bic sp, a2, #15 @ Set the new, aligned stack.
55 | #if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
56 | mov lr, pc @ Link for the return jump.
57 | bx a4 @ Call the function.
58 | #else
59 | blx a4 @ Call the function.
60 | #endif
61 | b EXIT @ Exit (argument implicit)
62 | SIZE(ctx_call)
63 |
64 | @ size_t
65 | @ ctx_mark(ctx_state *state, ctx_extra *extra, void **param);
66 | .text
67 | .globl NAME(ctx_mark)
68 | TYPE(ctx_mark)
69 | .align 2
70 | NAME(ctx_mark):
71 | #if (defined(__VFP_FP__) && !defined(__SOFTFP__))
72 | cmp a2, #0 @ Is extra NULL?
73 | vstmiane a2, {d8-d15} @ Save FP registers.
74 | #endif
75 |
76 | mov a2, a1 @ Move state to a free register.
77 | mov a1, #0 @ Set the return value and cnt.
78 | stmia a2, {a1, a3, v1-v8, sp-lr} @ Save cnt, param and GP regs.
79 |
80 | bx lr @ Return 0.
81 | SIZE(ctx_mark)
82 |
83 | @ void __CTX_NORETURN
84 | @ ctx_jump(ctx_state *state, ctx_extra *extra, void *param);
85 | .text
86 | .globl NAME(ctx_jump)
87 | TYPE(ctx_jump)
88 | .align 2
89 | NAME(ctx_jump):
90 | #if (defined(__VFP_FP__) && !defined(__SOFTFP__))
91 | cmp a2, #0 @ Is extra NULL?
92 | vldmiane a2, {d8-d15} @ Load FP registers.
93 | #endif
94 |
95 | mov a4, a1 @ Move state to a free register.
96 | ldmia a4, {a1, a2, v1-v8, sp-lr} @ Load cnt, param and GP regs.
97 | add a1, a1, #1 @ Increment cnt.
98 | str a1, [a4] @ Store cnt.
99 |
100 | cmp a2, #0 @ Is param NULL?
101 | strne a3, [a2] @ Conditionally save the param.
102 |
103 | bx lr @ Return cnt (implicit).
104 | SIZE(ctx_jump)
105 |
--------------------------------------------------------------------------------
/src/gas-mips-o32.S:
--------------------------------------------------------------------------------
1 | #
2 | # libctx - A cooperative multitasking library for C/C++
3 | #
4 | # Copyright 2013 Nathaniel McCallum
5 | # Portions Copyright 2009 Oliver Kowalke
6 | #
7 | # Distributed under the Boost Software License, Version 1.0.
8 | #
9 |
10 | # ---------------------------------------------------------
11 | # | ctx_state |
12 | # ---------------------------------------------------------
13 | # | 0x00 | 0x04 | 0x08 | 0x0c | 0x10 | 0x14 | 0x18 | 0x1c |
14 | # ---------------------------------------------------------
15 | # | s0 | s1 | s2 | s3 | s4 | s5 | s6 | s7 |
16 | # ---------------------------------------------------------
17 | # ---------------------------------------------------------
18 | # | 0x20 | 0x24 | 0x28 | 0x2c | 0x30 | 0x34 | 0x38 | 0x3c |
19 | # ---------------------------------------------------------
20 | # | fp | sp | ra | prm | cnt | |
21 | # ---------------------------------------------------------
22 |
23 | # ---------------------------------------------------------
24 | # | ctx_extra |
25 | # ---------------------------------------------------------
26 | # | 0x00 | 0x04 | 0x08 | 0x0c | 0x10 | 0x14 | 0x18 | 0x1c |
27 | # ---------------------------------------------------------
28 | # | f20-f21 | f22-f23 | f24-f25 | f26-f27 |
29 | # ---------------------------------------------------------
30 | # ---------------------------------------------------------
31 | # | 0x20 | 0x24 | 0x28 | 0x2c | |
32 | # ---------------------------------------------------------
33 | # | f28-f29 | f30-f31 | |
34 | # ---------------------------------------------------------
35 |
36 | # void __CTX_NORETURN
37 | # ctx_call(void *param, ctx_stack stack, int (*func)(void *param));
38 | .text
39 | .globl ctx_call
40 | .type ctx_call, @function
41 | .align 2
42 | .ent ctx_call
43 | ctx_call:
44 | li $t0, -16
45 | and $t0, $a1, $t0 # Align stack.
46 |
47 | addiu $sp, $t0, -32 # Push stack (incl. shadow space).
48 | sw $gp, 28($sp) # Save $gp for later recall.
49 |
50 | move $t9, $a3 # Move func into $t9.
51 | jalr $t9 # Call func.
52 |
53 | lw $gp, 28($sp) # Get $gp.
54 | lw $t9, %call16(_exit)($gp) # Get function address.
55 | move $a0, $v0 # Return value => argument.
56 | jalr $t9 # Call _exit().
57 | .end ctx_call
58 | .size ctx_call, .-ctx_call
59 |
60 | # size_t
61 | # ctx_mark(ctx_state *state, ctx_extra *extra, void **param);
62 | .text
63 | .globl ctx_mark
64 | .type ctx_mark, @function
65 | .align 2
66 | .ent ctx_mark
67 | ctx_mark:
68 | sw $s0, 0x00($a0) # Save s0.
69 | sw $s1, 0x04($a0) # Save s1.
70 | sw $s2, 0x08($a0) # Save s2.
71 | sw $s3, 0x0c($a0) # Save s3.
72 | sw $s4, 0x10($a0) # Save s4.
73 | sw $s5, 0x14($a0) # Save s5.
74 | sw $s6, 0x18($a0) # Save s6.
75 | sw $s7, 0x1c($a0) # Save s7.
76 | sw $fp, 0x20($a0) # Save fp.
77 | sw $sp, 0x24($a0) # Save sp.
78 | sw $ra, 0x28($a0) # Save ra.
79 | sw $a2, 0x2c($a0) # Save prm.
80 | sw $zero, 0x30($a0) # Save cnt.
81 |
82 | #if defined(__mips_hard_float)
83 | beqz $a1, noext0 # Is extra NULL?
84 | s.d $f20, 0x00($a1) # Save f20-f21.
85 | s.d $f22, 0x08($a1) # Save f22-f23.
86 | s.d $f24, 0x10($a1) # Save f24-f25.
87 | s.d $f26, 0x18($a1) # Save f26-f27.
88 | s.d $f28, 0x20($a1) # Save f28-f29.
89 | s.d $f30, 0x28($a1) # Save f30-f31.
90 | noext0:
91 | #endif
92 |
93 | move $v0, $zero # Return 0.
94 | jr $ra
95 | .end ctx_mark
96 | .size ctx_mark, .-ctx_mark
97 |
98 | # void __CTX_NORETURN
99 | # ctx_jump(ctx_state *state, ctx_extra *extra, void *param);
100 | .text
101 | .globl ctx_jump
102 | .type ctx_jump, @function
103 | .align 2
104 | .ent ctx_jump
105 | ctx_jump:
106 | lw $s0, 0x00($a0) # Load s0.
107 | lw $s1, 0x04($a0) # Load s1.
108 | lw $s2, 0x08($a0) # Load s2.
109 | lw $s3, 0x0c($a0) # Load s3.
110 | lw $s4, 0x10($a0) # Load s4.
111 | lw $s5, 0x14($a0) # Load s5.
112 | lw $s6, 0x18($a0) # Load s6.
113 | lw $s7, 0x1c($a0) # Load s7.
114 | lw $fp, 0x20($a0) # Load fp.
115 | lw $sp, 0x24($a0) # Load sp.
116 | lw $ra, 0x28($a0) # Load ra.
117 |
118 | #if defined(__mips_hard_float)
119 | beqz $a1, noext1 # Is extra NULL?
120 | l.d $f20, 0x00($a1) # Load f20-f21.
121 | l.d $f22, 0x08($a1) # Load f22-f23.
122 | l.d $f24, 0x10($a1) # Load f24-f25.
123 | l.d $f26, 0x18($a1) # Load f26-f27.
124 | l.d $f28, 0x20($a1) # Load f28-f29.
125 | l.d $f30, 0x28($a1) # Load f30-f31.
126 | noext1:
127 | #endif
128 |
129 | lw $t0, 0x2c($a0) # Load param.
130 | beqz $t0, noparam # Skip param on NULL.
131 | sw $a2, ($t0) # Set param.
132 | noparam:
133 |
134 | lw $v0, 0x30($a0) # Load cnt.
135 | addiu $v0, $v0, 1 # Increment cnt.
136 | sw $v0, 0x30($a0) # Save cnt.
137 | jr $ra # Return cnt.
138 | .end ctx_jump
139 | .size ctx_jump, .-ctx_jump
140 |
--------------------------------------------------------------------------------
/src/gas-ppc-sysv.S:
--------------------------------------------------------------------------------
1 | #
2 | # libctx - A cooperative multitasking library for C/C++
3 | #
4 | # Copyright 2013 Nathaniel McCallum
5 | # Portions Copyright 2009 Oliver Kowalke
6 | #
7 | # Distributed under the Boost Software License, Version 1.0.
8 | #
9 |
10 | # ---------------------------------------------------------
11 | # | ctx_state |
12 | # ---------------------------------------------------------
13 | # | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
14 | # ---------------------------------------------------------
15 | # | r13 | r14 | r15 | r16 | r17 | r18 | r19 | r20 |
16 | # ---------------------------------------------------------
17 | # ---------------------------------------------------------
18 | # | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
19 | # ---------------------------------------------------------
20 | # | r21 | r22 | r23 | r24 | r25 | r26 | r27 | r28 |
21 | # ---------------------------------------------------------
22 | # ---------------------------------------------------------
23 | # | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | # ---------------------------------------------------------
25 | # | r29 | r30 | r31 | sp | cr | lr | prm | cnt |
26 | # ---------------------------------------------------------
27 |
28 | # ---------------------------------------------------------
29 | # | ctx_extra |
30 | # ---------------------------------------------------------
31 | # | 0x00 | 0x08 | 0x10 | 0x18 | 0x20 | 0x28 | 0x30 | 0x38 |
32 | # ---------------------------------------------------------
33 | # | f14 | f15 | f16 | f17 | f18 | f19 | f20 | f21 |
34 | # ---------------------------------------------------------
35 | # ---------------------------------------------------------
36 | # | 0x40 | 0x48 | 0x50 | 0x58 | 0x60 | 0x68 | 0x70 | 0x78 |
37 | # ---------------------------------------------------------
38 | # | f22 | f23 | f24 | f25 | f26 | f27 | f28 | f29 |
39 | # ---------------------------------------------------------
40 | # ---------------------------------------------------------
41 | # | 0x80 | 0x88 | 0x90 | |
42 | # ---------------------------------------------------------
43 | # | f30 | f31 | fpscr| |
44 | # ---------------------------------------------------------
45 |
46 | #ifdef CTX_64BIT
47 | # define NAME(name) .name
48 | # define OFFSET(r, o) (o * 8)(r)
49 | # define lwz ld
50 | # define stw std
51 | # define clrrwi clrrdi
52 | # define cmpwi cmpdi
53 | #else
54 | # define NAME(name) name
55 | # define OFFSET(r, o) (o * 4)(r)
56 | #endif
57 |
58 | # void __CTX_NORETURN
59 | # ctx_call(void *param, ctx_stack stack, int (*func)(void *param));
60 | .text
61 | .align 2
62 | .globl ctx_call
63 | .type ctx_call, @function
64 | #ifdef CTX_64BIT
65 | .section ".opd", "aw"
66 | .align 3
67 | ctx_call:
68 | .quad .ctx_call, .TOC.@tocbase, 0
69 | .size ctx_call, 24
70 | .previous
71 | .ctx_call:
72 | ld %r5, 0(%r6) # Get entry point.
73 | ld %r2, 8(%r6) # Get TOC base address.
74 | ld %r11, 16(%r6) # Get environment pointer.
75 | #else
76 | ctx_call:
77 | lwz %r4, 0(%r4) # Get the stack pointer from the struct.
78 | #endif
79 |
80 | clrrwi %r4, %r4, 4 # Align the stack.
81 | subi %r1, %r4, 64 # Create parameter and linkage area.
82 |
83 | mtctr %r5
84 | bctrl # Call func().
85 | bl _exit # Call _exit().
86 | nop
87 | .size NAME(ctx_call), .-NAME(ctx_call)
88 |
89 | # size_t
90 | # ctx_mark(ctx_state *state, ctx_extra *extra, void **param);
91 | .text
92 | .align 2
93 | .globl ctx_mark
94 | .type ctx_mark, @function
95 | #ifdef CTX_64BIT
96 | .section ".opd", "aw"
97 | .align 3
98 | ctx_mark:
99 | .quad .ctx_mark, .TOC.@tocbase, 0
100 | .size ctx_mark, 24
101 | .previous
102 | .ctx_mark:
103 | #else
104 | ctx_mark:
105 | #endif
106 | mfcr %r6 # Get cr.
107 | mflr %r7 # Get lr.
108 | li %r8, 0 # Get cnt.
109 | stw %r13, OFFSET(%r3, 0) # Save r13.
110 | stw %r14, OFFSET(%r3, 1) # Save r14.
111 | stw %r15, OFFSET(%r3, 2) # Save r15.
112 | stw %r16, OFFSET(%r3, 3) # Save r16.
113 | stw %r17, OFFSET(%r3, 4) # Save r17.
114 | stw %r18, OFFSET(%r3, 5) # Save r18.
115 | stw %r19, OFFSET(%r3, 6) # Save r19.
116 | stw %r20, OFFSET(%r3, 7) # Save r20.
117 | stw %r21, OFFSET(%r3, 8) # Save r21.
118 | stw %r22, OFFSET(%r3, 9) # Save r22.
119 | stw %r23, OFFSET(%r3, 10) # Save r23.
120 | stw %r24, OFFSET(%r3, 11) # Save r24.
121 | stw %r25, OFFSET(%r3, 12) # Save r25.
122 | stw %r26, OFFSET(%r3, 13) # Save r26.
123 | stw %r27, OFFSET(%r3, 14) # Save r27.
124 | stw %r28, OFFSET(%r3, 15) # Save r28.
125 | stw %r29, OFFSET(%r3, 16) # Save r29.
126 | stw %r30, OFFSET(%r3, 17) # Save r30.
127 | stw %r31, OFFSET(%r3, 18) # Save r31.
128 | stw %r1, OFFSET(%r3, 19) # Save sp.
129 | stw %r6, OFFSET(%r3, 20) # Save cr.
130 | stw %r7, OFFSET(%r3, 21) # Save lr.
131 | stw %r5, OFFSET(%r3, 22) # Save prm.
132 | stw %r8, OFFSET(%r3, 23) # Save cnt.
133 |
134 | cmpwi cr0, %r4, 0 # Is extra NULL?
135 | beq cr0, noext0
136 | mffs %f0 # Get fpscr.
137 | stfd %f14, 0x00(%r4) # Save f14.
138 | stfd %f15, 0x08(%r4) # Save f15.
139 | stfd %f16, 0x10(%r4) # Save f16.
140 | stfd %f17, 0x18(%r4) # Save f17.
141 | stfd %f18, 0x20(%r4) # Save f18.
142 | stfd %f19, 0x28(%r4) # Save f19.
143 | stfd %f20, 0x30(%r4) # Save f20.
144 | stfd %f21, 0x38(%r4) # Save f21.
145 | stfd %f22, 0x40(%r4) # Save f22.
146 | stfd %f23, 0x48(%r4) # Save f23.
147 | stfd %f24, 0x50(%r4) # Save f24.
148 | stfd %f25, 0x58(%r4) # Save f25.
149 | stfd %f26, 0x60(%r4) # Save f26.
150 | stfd %f27, 0x68(%r4) # Save f27.
151 | stfd %f28, 0x70(%r4) # Save f28.
152 | stfd %f29, 0x78(%r4) # Save f29.
153 | stfd %f30, 0x80(%r4) # Save f30.
154 | stfd %f31, 0x88(%r4) # Save f31.
155 | stfd %f0, 0x90(%r4) # Save fpscr.
156 | noext0:
157 |
158 | li %r3, 0 # Return cnt.
159 | blr
160 | .size NAME(ctx_mark), .-NAME(ctx_mark)
161 |
162 | # void __CTX_NORETURN
163 | # ctx_jump(ctx_state *state, ctx_extra *extra, void *param);
164 | .text
165 | .align 2
166 | .globl ctx_jump
167 | .type ctx_jump, @function
168 | #ifdef CTX_64BIT
169 | .section ".opd", "aw"
170 | .align 3
171 | ctx_jump:
172 | .quad .ctx_jump, .TOC.@tocbase, 0
173 | .size ctx_jump, 24
174 | .previous
175 | .ctx_jump:
176 | #else
177 | ctx_jump:
178 | #endif
179 | lwz %r13, OFFSET(%r3, 0) # Load r13.
180 | lwz %r14, OFFSET(%r3, 1) # Load r14.
181 | lwz %r15, OFFSET(%r3, 2) # Load r15.
182 | lwz %r16, OFFSET(%r3, 3) # Load r16.
183 | lwz %r17, OFFSET(%r3, 4) # Load r17.
184 | lwz %r18, OFFSET(%r3, 5) # Load r18.
185 | lwz %r19, OFFSET(%r3, 6) # Load r19.
186 | lwz %r20, OFFSET(%r3, 7) # Load r20.
187 | lwz %r21, OFFSET(%r3, 8) # Load r21.
188 | lwz %r22, OFFSET(%r3, 9) # Load r22.
189 | lwz %r23, OFFSET(%r3, 10) # Load r23.
190 | lwz %r24, OFFSET(%r3, 11) # Load r24.
191 | lwz %r25, OFFSET(%r3, 12) # Load r25.
192 | lwz %r26, OFFSET(%r3, 13) # Load r26.
193 | lwz %r27, OFFSET(%r3, 14) # Load r27.
194 | lwz %r28, OFFSET(%r3, 15) # Load r28.
195 | lwz %r29, OFFSET(%r3, 16) # Load r29.
196 | lwz %r30, OFFSET(%r3, 17) # Load r30.
197 | lwz %r31, OFFSET(%r3, 18) # Load r31.
198 | lwz %r1, OFFSET(%r3, 19) # Load sp.
199 | lwz %r6, OFFSET(%r3, 20) # Load cr.
200 | lwz %r7, OFFSET(%r3, 21) # Load lr.
201 | mtcr %r6 # Set cr.
202 | mtlr %r7 # Set lr.
203 |
204 | cmpwi cr0, %r4, 0 # Is extra NULL?
205 | beq cr0, noext1
206 | lfd %f14, 0x00(%r4) # Load f14.
207 | lfd %f15, 0x08(%r4) # Load f15.
208 | lfd %f16, 0x10(%r4) # Load f16.
209 | lfd %f17, 0x18(%r4) # Load f17.
210 | lfd %f18, 0x20(%r4) # Load f18.
211 | lfd %f19, 0x28(%r4) # Load f19.
212 | lfd %f20, 0x30(%r4) # Load f20.
213 | lfd %f21, 0x38(%r4) # Load f21.
214 | lfd %f22, 0x40(%r4) # Load f22.
215 | lfd %f23, 0x48(%r4) # Load f23.
216 | lfd %f24, 0x50(%r4) # Load f24.
217 | lfd %f25, 0x58(%r4) # Load f25.
218 | lfd %f26, 0x60(%r4) # Load f26.
219 | lfd %f27, 0x68(%r4) # Load f27.
220 | lfd %f28, 0x70(%r4) # Load f28.
221 | lfd %f29, 0x78(%r4) # Load f29.
222 | lfd %f30, 0x80(%r4) # Load f30.
223 | lfd %f31, 0x88(%r4) # Load f31.
224 | lfd %f0, 0x90(%r4) # Load fpscr.
225 | mtfsf 0x9f, %f0 # Set fpscr.
226 | noext1:
227 |
228 | lwz %r8, OFFSET(%r3, 22) # Load prm.
229 | cmpwi cr0, %r8, 0 # Is param NULL?
230 | beq cr0, noparam
231 | stw %r5, 0x00(%r8) # Set param.
232 | noparam:
233 |
234 | lwz %r9, OFFSET(%r3, 23) # Load cnt.
235 | addi %r9, %r9, 1 # Increment cnt.
236 | stw %r9, OFFSET(%r3, 23) # Save cnt.
237 | mr %r3, %r9 # Return cnt.
238 | mtctr %r7
239 | bctr
240 | .size NAME(ctx_jump), .-NAME(ctx_jump)
241 |
--------------------------------------------------------------------------------
/src/gas-sparc-sysv.S:
--------------------------------------------------------------------------------
1 | !
2 | ! libctx - A cooperative multitasking library for C/C++
3 | !
4 | ! Copyright 2013 Nathaniel McCallum
5 | ! Portions Copyright 2013 Martin Husemann
6 | !
7 | ! Distributed under the Boost Software License, Version 1.0.
8 | !
9 |
10 | ! ---------------------------------------------------------
11 | ! | ctx_state |
12 | ! ---------------------------------------------------------
13 | ! | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
14 | ! ---------------------------------------------------------
15 | ! | l0 | l1 | l2 | l3 | l4 | l5 | l6 | l7 |
16 | ! ---------------------------------------------------------
17 | ! | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
18 | ! ---------------------------------------------------------
19 | ! | i0 | i1 | i2 | i3 | i4 | i5 | i6 | i7 |
20 | ! ---------------------------------------------------------
21 | ! | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 |
22 | ! ---------------------------------------------------------
23 | ! | sp | o7 | g1 | g2 | g3 | g6 | g7 | prm |
24 | ! ---------------------------------------------------------
25 | ! | 24 | |
26 | ! ---------------------------------------------------------
27 | ! | cnt | |
28 | ! ---------------------------------------------------------
29 | !
30 | ! -----------------------------------------------------------------
31 | ! | ctx_extra (32bit) |
32 | ! -----------------------------------------------------------------
33 | ! | 0x000 | 0x004 | 0x008 | 0x00c | 0x010 | 0x014 | 0x018 | 0x01c |
34 | ! -----------------------------------------------------------------
35 | ! | f0-f1 | f2-f3 | f4-f5 | f6-f7 |
36 | ! -----------------------------------------------------------------
37 | ! -----------------------------------------------------------------
38 | ! | 0x020 | 0x024 | 0x028 | 0x02c | 0x030 | 0x034 | 0x038 | 0x03c |
39 | ! -----------------------------------------------------------------
40 | ! | f8-f9 | f10-f11 | f12-f13 | f14-15 |
41 | ! -----------------------------------------------------------------
42 | ! -----------------------------------------------------------------
43 | ! | 0x040 | |
44 | ! -----------------------------------------------------------------
45 | ! | fsr | |
46 | ! -----------------------------------------------------------------
47 | !
48 | ! -----------------------------------------------------------------
49 | ! | ctx_extra (64bit) |
50 | ! -----------------------------------------------------------------
51 | ! | 0x000 | 0x008 | 0x010 | 0x018 | 0x020 | 0x028 | 0x030 | 0x038 |
52 | ! -----------------------------------------------------------------
53 | ! | f0-f15 |
54 | ! -----------------------------------------------------------------
55 | ! -----------------------------------------------------------------
56 | ! | 0x040 | 0x048 | 0x050 | 0x058 | 0x060 | 0x068 | 0x070 | 0x078 |
57 | ! -----------------------------------------------------------------
58 | ! | f16-f31 |
59 | ! -----------------------------------------------------------------
60 | ! -----------------------------------------------------------------
61 | ! | 0x080 | 0x088 | 0x090 | 0x098 | 0x0a0 | 0x0a8 | 0x0b0 | 0x0b8 |
62 | ! -----------------------------------------------------------------
63 | ! | f32-f47 |
64 | ! -----------------------------------------------------------------
65 | ! -----------------------------------------------------------------
66 | ! | 0x0c0 | 0x0c8 | 0x0d0 | 0x0d8 | 0x0e0 | 0x0e8 | 0x0f0 | 0x0f8 |
67 | ! -----------------------------------------------------------------
68 | ! | f48-f63 |
69 | ! -----------------------------------------------------------------
70 | ! -----------------------------------------------------------------
71 | ! | 0x100 | 0x108 | |
72 | ! -----------------------------------------------------------------
73 | ! | fprs | fsr | |
74 | ! -----------------------------------------------------------------
75 |
76 | #ifdef CTX_64BIT
77 | # define ALIGN 64
78 | # define WINSZ 176+2048-1
79 | # define OFFSET(r, i) [r + (8 * i)]
80 | # define func %o3
81 | # define st stx
82 | # define ld ldx
83 | #else
84 | # define ALIGN 8
85 | # define WINSZ 96
86 | # define OFFSET(r, i) [r + (4 * i)]
87 | # define func %o2
88 | #endif
89 |
90 | .register %g2, #ignore
91 | .register %g3, #ignore
92 | .register %g6, #ignore
93 |
94 | ! void __CTX_NORETURN
95 | ! ctx_call(void *param, ctx_stack stack, int (*func)(void *param));
96 | .text
97 | .globl ctx_call
98 | .align 4
99 | .type ctx_call, @function
100 | ctx_call:
101 | #ifndef CTX_64BIT
102 | ld [%o1], %o1 ! Get stack.stack.
103 | #endif
104 | andn %o1, ALIGN-1, %o1 ! Align the stack.
105 |
106 | call func ! Call the function.
107 | sub %o1, WINSZ, %sp ! Allocate register window.
108 | call _exit
109 | nop
110 | .size ctx_call, .-ctx_call
111 |
112 | ! size_t
113 | ! ctx_mark(ctx_state *state, ctx_extra *extra, void **param);
114 | .text
115 | .globl ctx_mark
116 | .align 4
117 | .type ctx_mark, @function
118 | ctx_mark:
119 | st %l0, OFFSET(%o0, 0) ! Save l0.
120 | st %l1, OFFSET(%o0, 1) ! Save l1.
121 | st %l2, OFFSET(%o0, 2) ! Save l2.
122 | st %l3, OFFSET(%o0, 3) ! Save l3.
123 | st %l4, OFFSET(%o0, 4) ! Save l4.
124 | st %l5, OFFSET(%o0, 5) ! Save l5.
125 | st %l6, OFFSET(%o0, 6) ! Save l6.
126 | st %l7, OFFSET(%o0, 7) ! Save l7.
127 | st %i0, OFFSET(%o0, 8) ! Save i0.
128 | st %i1, OFFSET(%o0, 9) ! Save i1.
129 | st %i2, OFFSET(%o0, 10) ! Save i2.
130 | st %i3, OFFSET(%o0, 11) ! Save i3.
131 | st %i4, OFFSET(%o0, 12) ! Save i4.
132 | st %i5, OFFSET(%o0, 13) ! Save i5.
133 | st %i6, OFFSET(%o0, 14) ! Save i6.
134 | st %i7, OFFSET(%o0, 15) ! Save i7.
135 | st %sp, OFFSET(%o0, 16) ! Save sp.
136 | st %o7, OFFSET(%o0, 17) ! Save o7.
137 | st %g1, OFFSET(%o0, 18) ! Save g1.
138 | st %g2, OFFSET(%o0, 19) ! Save g2.
139 | st %g3, OFFSET(%o0, 20) ! Save g3.
140 | st %g6, OFFSET(%o0, 21) ! Save g6.
141 | st %g7, OFFSET(%o0, 22) ! Save g7.
142 | st %o2, OFFSET(%o0, 23) ! Save prm.
143 | st %g0, OFFSET(%o0, 24) ! Save cnt.
144 |
145 | cmp %o1, 0 ! Is extra NULL?
146 | bz noext0
147 | nop
148 | #ifdef CTX_64BIT
149 | rd %fprs, %o4 ! Get fprs.
150 | stda %f0, [%o1] 0xf0 ! Save f00-f15.
151 | add %o1, 64, %o1 ! Move to next block.
152 | stda %f16, [%o1] 0xf0 ! Save f16-f31.
153 | add %o1, 64, %o1 ! Move to next block.
154 | stda %f32, [%o1] 0xf0 ! Save f32-f47.
155 | add %o1, 64, %o1 ! Move to next block.
156 | stda %f48, [%o1] 0xf0 ! Save f48-f64.
157 | add %o1, 64, %o1 ! Move to next block.
158 | stx %o4, [%o1 + 0x00] ! Save fprs.
159 | stx %fsr, [%o1 + 0x08] ! Save fsr.
160 | #else
161 | std %f0, [%o1 + 0x00] ! Save f0.
162 | std %f2, [%o1 + 0x08] ! Save f2.
163 | std %f4, [%o1 + 0x10] ! Save f4.
164 | std %f6, [%o1 + 0x18] ! Save f6.
165 | std %f8, [%o1 + 0x20] ! Save f8.
166 | std %f10, [%o1 + 0x28] ! Save f10.
167 | std %f12, [%o1 + 0x30] ! Save f12.
168 | std %f14, [%o1 + 0x38] ! Save f14.
169 | st %fsr, [%o1 + 0x40] ! Save fsr.
170 | #endif
171 | noext0:
172 |
173 | jmp %o7 + 8
174 | mov %g0, %o0 ! Return 0.
175 | .size ctx_mark, .-ctx_mark
176 |
177 | ! void __CTX_NORETURN
178 | ! ctx_jump(ctx_state *state, ctx_extra *extra, void *param);
179 | .text
180 | .globl ctx_jump
181 | .align 4
182 | .type ctx_jump, @function
183 | ctx_jump:
184 | ld OFFSET(%o0, 0), %l0 ! Load l0.
185 | ld OFFSET(%o0, 1), %l1 ! Load l1.
186 | ld OFFSET(%o0, 2), %l2 ! Load l2.
187 | ld OFFSET(%o0, 3), %l3 ! Load l3.
188 | ld OFFSET(%o0, 4), %l4 ! Load l4.
189 | ld OFFSET(%o0, 5), %l5 ! Load l5.
190 | ld OFFSET(%o0, 6), %l6 ! Load l6.
191 | ld OFFSET(%o0, 7), %l7 ! Load l7.
192 | ld OFFSET(%o0, 8), %i0 ! Load i0.
193 | ld OFFSET(%o0, 9), %i1 ! Load i1.
194 | ld OFFSET(%o0, 10), %i2 ! Load i2.
195 | ld OFFSET(%o0, 11), %i3 ! Load i3.
196 | ld OFFSET(%o0, 12), %i4 ! Load i4.
197 | ld OFFSET(%o0, 13), %i5 ! Load i5.
198 | ld OFFSET(%o0, 14), %i6 ! Load i6.
199 | ld OFFSET(%o0, 15), %i7 ! Load i7.
200 | ld OFFSET(%o0, 16), %sp ! Load sp.
201 | ld OFFSET(%o0, 17), %o7 ! Load o7.
202 | ld OFFSET(%o0, 18), %g1 ! Load g1.
203 | ld OFFSET(%o0, 19), %g2 ! Load g2.
204 | ld OFFSET(%o0, 20), %g3 ! Load g3.
205 | ld OFFSET(%o0, 21), %g6 ! Load g6.
206 | ld OFFSET(%o0, 22), %g7 ! Load g7.
207 |
208 | cmp %o1, 0 ! Is extra NULL?
209 | bz noext1
210 | nop
211 | #ifdef CTX_64BIT
212 | ldda [%o1] 0xf0, %f0 ! Load f00-f15.
213 | add %o1, 64, %o1 ! Move to next block.
214 | ldda [%o1] 0xf0, %f16 ! Load f16-f31.
215 | add %o1, 64, %o1 ! Move to next block.
216 | ldda [%o1] 0xf0, %f32 ! Load f32-f47.
217 | add %o1, 64, %o1 ! Move to next block.
218 | ldda [%o1] 0xf0, %f48 ! Load f48-f63.
219 | add %o1, 64, %o1 ! Move to next block.
220 | ldx [%o1 + 0x00], %o3 ! Load fprs.
221 | ldx [%o1 + 0x08], %fsr ! Load fsr.
222 | wr %o3, 0, %fprs ! Set fprs.
223 | #else
224 | ldd [%o1 + 0x00], %f0 ! Load f0.
225 | ldd [%o1 + 0x08], %f2 ! Load f2.
226 | ldd [%o1 + 0x10], %f4 ! Load f4.
227 | ldd [%o1 + 0x18], %f6 ! Load f6.
228 | ldd [%o1 + 0x20], %f8 ! Load f8.
229 | ldd [%o1 + 0x28], %f10 ! Load f10.
230 | ldd [%o1 + 0x30], %f12 ! Load f12.
231 | ldd [%o1 + 0x38], %f14 ! Load f14.
232 | ld [%o1 + 0x40], %fsr ! Load fsr.
233 | #endif
234 | noext1:
235 |
236 | ld OFFSET(%o0, 23), %o3 ! Load prm.
237 | cmp %o3, 0 ! Is prm NULL?
238 | bz noparam
239 | nop
240 | st %o2, [%o3] ! Set the param.
241 | noparam:
242 |
243 | ld OFFSET(%o0, 24), %o3 ! Load cnt.
244 | inc %o3 ! Increment cnt.
245 | st %o3, OFFSET(%o0, 24) ! Save cnt.
246 | jmp %o7 + 8 ! Return.
247 | mov %o3, %o0 ! Return cnt.
248 | .size ctx_jump, .-ctx_jump
249 |
--------------------------------------------------------------------------------
/src/gas-x86_32-sysv.S:
--------------------------------------------------------------------------------
1 | #
2 | # libctx - A cooperative multitasking library for C/C++
3 | #
4 | # Copyright 2013 Nathaniel McCallum
5 | # Portions Copyright 2009 Oliver Kowalke
6 | #
7 | # Distributed under the Boost Software License, Version 1.0.
8 | #
9 |
10 | # ---------------------------------------------------------
11 | # | 0x00 | 0x04 | 0x08 | 0x0c | 0x10 | 0x14 | 0x18 | 0x1c |
12 | # ---------------------------------------------------------
13 | # | edi | esi | ebx | ebp | esp | eip | prm | cnt |
14 | # ---------------------------------------------------------
15 | # Extended cpu state is stored via fxsave.
16 |
17 | #if defined(_WIN32)
18 | # define NAME(name) _ ## name
19 | # define TYPE(name) .def _ ## name; .scl 2; .type 32; .endef
20 | # define ALIGN 16
21 | # define SIZE(name) .size NAME(name), .-NAME(name)
22 | # define EXIT _exit
23 | #elif defined(__APPLE__)
24 | # define NAME(name) _ ## name
25 | # define TYPE(name)
26 | # define ALIGN 8
27 | # define SIZE(name)
28 | # define EXIT EXIT
29 | #else
30 | # define NAME(name) name
31 | # define TYPE(name) .type name, @function
32 | # define ALIGN 16
33 | # define SIZE(name) .size NAME(name), .-NAME(name)
34 | # define EXIT _exit@PLT
35 | #endif
36 |
37 | # void __CTX_NORETURN
38 | # ctx_call(void *param, ctx_stack stack, int (*func)(void *param));
39 | .text
40 | .globl NAME(ctx_call)
41 | TYPE(ctx_call)
42 | .align ALIGN
43 | NAME(ctx_call):
44 | mov 0x04(%esp), %eax # Get param.
45 | mov 0x10(%esp), %ecx # Get func.
46 |
47 | mov 0x08(%esp), %esp # Get stack.
48 | and $-16, %esp # Align the new stack.
49 |
50 | add $-16, %esp # Push stack with alignment for argument.
51 | mov %eax, (%esp) # Set the argument
52 | call *%ecx # Call the function.
53 |
54 | mov %eax, (%esp) # Set the argument
55 | call EXIT # Exit
56 | SIZE(ctx_call)
57 |
58 | # size_t
59 | # ctx_mark(ctx_state *state, ctx_extra *extra, void **param);
60 | .text
61 | .globl NAME(ctx_mark)
62 | TYPE(ctx_mark)
63 | .align ALIGN
64 | NAME(ctx_mark):
65 | pop %edx # Pop the return pointer.
66 |
67 | mov 0x00(%esp), %eax # Get state.
68 | mov 0x08(%esp), %ecx # Get param.
69 | mov %edi, 0x00(%eax) # Save edi.
70 | mov %esi, 0x04(%eax) # Save esi.
71 | mov %ebx, 0x08(%eax) # Save ebx.
72 | mov %ebp, 0x0c(%eax) # Save ebp.
73 | mov %esp, 0x10(%eax) # Save esp.
74 | mov %edx, 0x14(%eax) # Save eip.
75 | mov %ecx, 0x18(%eax) # Save prm.
76 | movl $0, 0x1c(%eax) # Save cnt.
77 |
78 | cmp $0, 0x04(%esp) # Is extra NULL?
79 | je noext0
80 | mov 0x04(%esp), %eax # Get extra.
81 | fxsave (%eax) # Do fxsave.
82 | noext0:
83 |
84 | mov $0, %eax # Return 0
85 | jmp *%edx
86 | SIZE(ctx_mark)
87 |
88 | # void __CTX_NORETURN
89 | # ctx_jump(ctx_state *state, ctx_extra *extra, void *param);
90 | .text
91 | .globl NAME(ctx_jump)
92 | TYPE(ctx_jump)
93 | .align ALIGN
94 | NAME(ctx_jump):
95 | mov 0x04(%esp), %ecx # Get state.
96 |
97 | cmp $0, 0x08(%esp) # Is extra NULL?
98 | je noext1
99 | mov 0x08(%esp), %eax # Get extra.
100 | fxrstor (%eax) # Do fxrstor.
101 | noext1:
102 |
103 | cmp $0, 0x18(%ecx) # Is param pointer NULL?
104 | je noparam
105 | mov 0x18(%ecx), %eax # Get param pointer.
106 | mov 0x0c(%esp), %edx # Get param.
107 | mov %edx, (%eax) # Set param.
108 | mov $0, %eax # Return false (if skipped, implicit).
109 | noparam:
110 |
111 | mov 0x00(%ecx), %edi # Load edi.
112 | mov 0x04(%ecx), %esi # Load esi.
113 | mov 0x08(%ecx), %ebx # Load ebx.
114 | mov 0x0c(%ecx), %ebp # Load ebp.
115 | mov 0x10(%ecx), %esp # Load esp.
116 | mov 0x14(%ecx), %edx # Load eip.
117 | mov 0x1c(%ecx), %eax # Load cnt.
118 |
119 | inc %eax # Increment cnt.
120 | mov %eax, 0x1c(%ecx) # Save cnt.
121 | jmp *%edx # Return cnt.
122 | SIZE(ctx_jump)
123 |
--------------------------------------------------------------------------------
/src/gas-x86_64-sysv.S:
--------------------------------------------------------------------------------
1 | #
2 | # libctx - A cooperative multitasking library for C/C++
3 | #
4 | # Copyright 2013 Nathaniel McCallum
5 | # Portions Copyright 2009 Oliver Kowalke
6 | #
7 | # Distributed under the Boost Software License, Version 1.0.
8 | #
9 |
10 | # -----------------------------------------------------------------------
11 | # | 0x00 | 0x08 | 0x10 | 0x18 | 0x20 | 0x28 | 0x30 | 0x38 | 0x40 | 0x48 |
12 | # -----------------------------------------------------------------------
13 | # | r12 | r13 | r14 | r15 | rbx | rbp | rsp | rip | prm | cnt |
14 | # -----------------------------------------------------------------------
15 | # Extended cpu state is stored via fxsave.
16 |
17 | #if defined(_WIN32) || defined(_WIN64)
18 | # define __NAME(name) _ ## name
19 | # define __TYPE(name) .def _ ## name; .scl 2; .type 32; .endef
20 | # define __ALIGN 16
21 | # define __SIZE(name) .size __NAME(name),.-__NAME(name)
22 | # define __EXIT _exit
23 | #elif defined(__APPLE__)
24 | # define __NAME(name) _ ## name
25 | # define __TYPE(name)
26 | # define __ALIGN 8
27 | # define __SIZE(name)
28 | # define __EXIT __exit
29 | #else
30 | # define __NAME(name) name
31 | # define __TYPE(name) .type name, @function
32 | # define __ALIGN 16
33 | # define __SIZE(name) .size __NAME(name),.-__NAME(name)
34 | # define __EXIT _exit@PLT
35 | #endif
36 |
37 | # void __CTX_NORETURN
38 | # ctx_call(void *param, ctx_stack stack, int (*func)(void *param));
39 | .text
40 | .globl __NAME(ctx_call)
41 | __TYPE(ctx_call)
42 | .align __ALIGN
43 | __NAME(ctx_call):
44 | mov %rsi, %rsp # Set the new stack address.
45 | and $-16, %rsp # Align the new stack.
46 | call *%rcx # Call the function.
47 | mov %rax, %rdi # Set the argument
48 | call __EXIT
49 | __SIZE(ctx_call)
50 |
51 | # size_t
52 | # ctx_mark(ctx_state *state, ctx_extra *extra, void **param);
53 | .text
54 | .globl __NAME(ctx_mark)
55 | __TYPE(ctx_mark)
56 | .align __ALIGN
57 | __NAME(ctx_mark):
58 | pop %rcx # Pop the return pointer.
59 |
60 | mov %r12, 0x00(%rdi) # Save r12.
61 | mov %r13, 0x08(%rdi) # Save r13.
62 | mov %r14, 0x10(%rdi) # Save r14.
63 | mov %r15, 0x18(%rdi) # Save r15.
64 | mov %rbx, 0x20(%rdi) # Save rbx.
65 | mov %rbp, 0x28(%rdi) # Save rbp.
66 | mov %rsp, 0x30(%rdi) # Save rsp.
67 | mov %rcx, 0x38(%rdi) # Save rip.
68 | mov %rdx, 0x40(%rdi) # Save prm.
69 | movq $0, 0x48(%rdi) # Save cnt.
70 |
71 | cmp $0, %rsi # Is extra NULL?
72 | je noext0
73 | fxsave (%rsi) # Do fxsave.
74 | noext0:
75 |
76 | mov $0, %rax # Return 0.
77 | jmp *%rcx
78 | __SIZE(ctx_mark)
79 |
80 | # void __CTX_NORETURN
81 | # ctx_jump(ctx_state *state, ctx_extra *extra, void *param);
82 | .text
83 | .globl __NAME(ctx_jump)
84 | __TYPE(ctx_jump)
85 | .align __ALIGN
86 | __NAME(ctx_jump):
87 | cmp $0, %rsi # Is extra NULL?
88 | je noext1
89 | fxrstor (%rsi) # Do fxrstor.
90 | noext1:
91 |
92 | mov 0x00(%rdi), %r12 # Load r12.
93 | mov 0x08(%rdi), %r13 # Load r13.
94 | mov 0x10(%rdi), %r14 # Load r14.
95 | mov 0x18(%rdi), %r15 # Load r15.
96 | mov 0x20(%rdi), %rbx # Load rbx.
97 | mov 0x28(%rdi), %rbp # Load rbp.
98 | mov 0x30(%rdi), %rsp # Load rsp.
99 | mov 0x38(%rdi), %rcx # Load rip.
100 | mov 0x40(%rdi), %rsi # Load prm.
101 | mov 0x48(%rdi), %rax # Load cnt.
102 |
103 | cmp $0, %rsi # Is prm NULL?
104 | je noparam
105 | mov %rdx, (%rsi) # Set param.
106 | noparam:
107 |
108 | inc %rax # Increment cnt.
109 | mov %rax, 0x48(%rdi) # Save cnt.
110 | jmp *%rcx # Return cnt.
111 | __SIZE(ctx_jump)
112 |
--------------------------------------------------------------------------------
/src/test.c:
--------------------------------------------------------------------------------
1 | /*
2 | * libctx - A cooperative multitasking library for C/C++
3 | *
4 | * Copyright 2013 Nathaniel McCallum
5 | *
6 | * Distributed under the Boost Software License, Version 1.0.
7 | */
8 |
9 | #include "ctx.h"
10 |
11 | #include
12 | #include
13 |
14 | struct bundle {
15 | ctx_state state;
16 | ctx_extra extra;
17 | };
18 |
19 | static int i;
20 |
21 | static int
22 | addfunc(struct bundle *param)
23 | {
24 | struct bundle bundle;
25 |
26 | if (ctx_mark(&bundle.state, &bundle.extra, ¶m) == 0)
27 | ctx_jump(¶m->state, ¶m->extra, &bundle);
28 |
29 | while (1) {
30 | i++;
31 | if (ctx_mark(&bundle.state, &bundle.extra, ¶m) == 0)
32 | ctx_jump(¶m->state, ¶m->extra, &bundle);
33 | }
34 |
35 | return 0;
36 | }
37 |
38 | static int
39 | subfunc(struct bundle *param)
40 | {
41 | struct bundle bundle;
42 |
43 | if (ctx_mark(&bundle.state, &bundle.extra, ¶m) == 0)
44 | ctx_jump(¶m->state, ¶m->extra, &bundle);
45 |
46 | while (1) {
47 | i--;
48 | if (ctx_mark(&bundle.state, &bundle.extra, ¶m) == 0)
49 | ctx_jump(¶m->state, ¶m->extra, &bundle);
50 | }
51 |
52 | return 0;
53 | }
54 |
55 | int
56 | main(int argc, const char **argv)
57 | {
58 | ctx_stack addstk = { NULL, 1 }, substk = { NULL, 1 };
59 | struct bundle bundle, *addbndl, *subbndl;
60 |
61 | assert(ctx_new(&addstk) == 0);
62 | assert(ctx_new(&substk) == 0);
63 |
64 | if (ctx_mark(&bundle.state, &bundle.extra, &addbndl) == 0)
65 | ctx_call(&bundle, addstk, addfunc);
66 | if (ctx_mark(&bundle.state, &bundle.extra, &subbndl) == 0)
67 | ctx_call(&bundle, substk, subfunc);
68 |
69 | if (ctx_mark(&bundle.state, &bundle.extra, &addbndl) == 0)
70 | ctx_jump(&addbndl->state, &addbndl->extra, &bundle);
71 | assert(i == 1);
72 |
73 | if (ctx_mark(&bundle.state, &bundle.extra, &addbndl) == 0)
74 | ctx_jump(&addbndl->state, &addbndl->extra, &bundle);
75 | assert(i == 2);
76 |
77 | if (ctx_mark(&bundle.state, &bundle.extra, &subbndl) == 0)
78 | ctx_jump(&subbndl->state, &subbndl->extra, &bundle);
79 | assert(i == 1);
80 |
81 | if (ctx_mark(&bundle.state, &bundle.extra, &addbndl) == 0)
82 | ctx_jump(&addbndl->state, &addbndl->extra, &bundle);
83 | assert(i == 2);
84 |
85 | if (ctx_mark(&bundle.state, &bundle.extra, &subbndl) == 0)
86 | ctx_jump(&subbndl->state, &subbndl->extra, &bundle);
87 | assert(i == 1);
88 |
89 | if (ctx_mark(&bundle.state, &bundle.extra, &subbndl) == 0)
90 | ctx_jump(&subbndl->state, &subbndl->extra, &bundle);
91 | assert(i == 0);
92 |
93 | /* Ensure:
94 | * 1. that multiple jumps can occur on a single save.
95 | * 2. proper behavior when the ctx_mark() param pointer is NULL. */
96 | while (ctx_mark(&bundle.state, &bundle.extra, NULL) < 3) {
97 | i++;
98 | ctx_jump(&bundle.state, &bundle.extra, &bundle);
99 | }
100 | assert(i == 3);
101 |
102 | ctx_free(addstk);
103 | ctx_free(substk);
104 | return 0;
105 | }
106 |
--------------------------------------------------------------------------------