├── .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 | 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 | 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 | --------------------------------------------------------------------------------