├── .gitignore ├── .gitmodules ├── .travis.yml ├── INSTALL ├── LICENSE ├── Makefile.am ├── NEWS ├── README.md ├── bench ├── Makefile.am ├── b01-asapwto.tcc └── b02-string.tcc ├── bootstrap.sh ├── compiler ├── COPYING ├── Makefile.am ├── output.cc ├── parse.yy ├── processor.cc ├── scan.ll ├── tame.cc └── tame.hh ├── configure.ac ├── doc ├── Doxyfile ├── Makefile.am ├── tamer.1 ├── tamer.3 ├── tamer.3.md └── tamer_fd.3 ├── ex ├── Makefile.am ├── ex6.tt ├── md5.c ├── md5.h ├── osptracker.tcc ├── tamer-echosrv.tcc ├── tamer-httpd.tcc ├── tamer-wsecho.tcc └── tamer-yes.tcc ├── knot ├── Makefile.am ├── README ├── cache2.hh ├── cache2.tt ├── http.hh ├── http.tt ├── httphdrs.h ├── input.hh ├── input.tt ├── knot.tt └── refptr.hh ├── tamer ├── Makefile.am ├── adapter.hh ├── autoconf.h.in ├── bufferedio.hh ├── bufferedio.tcc ├── channel.hh ├── dinternal.cc ├── dinternal.hh ├── dlibev.cc ├── dlibevent.cc ├── dns.hh ├── dns.tt ├── driver.hh ├── dsignal.cc ├── dtamer.cc ├── event.hh ├── fd.hh ├── fd.tcc ├── fdh.hh ├── fdh.tt ├── fdhelp.cc ├── fdhmsg.cc ├── fdhmsg.hh ├── http.hh ├── http.tcc ├── http_parser.c ├── lock.hh ├── lock.tcc ├── ref.hh ├── rendezvous.hh ├── tamer.hh ├── tamer.pc.in ├── websocket.hh ├── websocket.tcc ├── xadapter.cc ├── xadapter.hh ├── xbase.cc ├── xbase.hh └── xdriver.hh └── test ├── Makefile.am ├── t01.tcc ├── t01.testie ├── t02.tt ├── t03.tcc ├── t03.testie ├── t04.tt ├── t05.testie ├── t05.tt ├── t06.tcc ├── t06.testie ├── t07.tcc ├── t07.testie ├── t08.tcc ├── t08.testie ├── t09.tcc ├── t09.testie ├── t10.tcc ├── t10.testie ├── t11.tcc ├── t11.testie ├── t12.tcc ├── t12.testie ├── t13.tcc ├── t13.testie ├── t14.tcc ├── t14.testie ├── t15.tcc ├── t15.testie ├── t16.tcc ├── t16.testie ├── t17.tcc ├── t17.testie ├── t18.tcc ├── t18.testie ├── t19.tcc ├── t19.testie ├── t20.tcc ├── t20.testie ├── t21.tcc ├── t21.testie ├── t22.tcc ├── t22.testie ├── t23.tcc ├── t23.testie ├── t24.tcc ├── t24.testie ├── t25.tcc ├── t25.testie ├── t26.tcc ├── t26.testie ├── t27.tcc ├── t27.testie ├── t28.tcc ├── t28.testie ├── t29.tcc ├── t29.testie ├── t30.tcc └── testie /.gitignore: -------------------------------------------------------------------------------- 1 | *.dSYM 2 | *.la 3 | *.lo 4 | *.o 5 | .deps 6 | .libs 7 | gmon.out 8 | 9 | /Makefile 10 | /Makefile.in 11 | /aclocal.m4 12 | /autom4te* 13 | /compile 14 | /config.guess 15 | /config.h 16 | /config.h.in 17 | /config.h.in~ 18 | /config.log 19 | /config.status 20 | /config.sub 21 | /configure 22 | /configure~ 23 | /depcomp 24 | /install-sh 25 | /libtool 26 | /ltmain.sh 27 | /missing 28 | /stamp-h* 29 | /ylwrap 30 | 31 | /compiler/Makefile 32 | /compiler/Makefile.in 33 | /compiler/parse.cc 34 | /compiler/parse.hh 35 | /compiler/scan.cc 36 | /compiler/tamer 37 | 38 | /tamer/Makefile 39 | /tamer/Makefile.in 40 | /tamer/autoconf.h 41 | /tamer/bufferedio.cc 42 | /tamer/dns.cc 43 | /tamer/fd.cc 44 | /tamer/fdh.cc 45 | /tamer/http.cc 46 | /tamer/lock.cc 47 | /tamer/stamp-h* 48 | /tamer/tamer.pc 49 | /tamer/tamerfdh 50 | /tamer/websocket.cc 51 | 52 | /doc/Makefile 53 | /doc/Makefile.in 54 | 55 | /ex/Makefile 56 | /ex/Makefile.in 57 | /ex/ex[0-9] 58 | /ex/ex[1-6].cc 59 | /ex/osptracker 60 | /ex/osptracker.cc 61 | /ex/tamer-echosrv 62 | /ex/tamer-echosrv.cc 63 | /ex/tamer-httpd 64 | /ex/tamer-httpd.cc 65 | /ex/tamer-wsecho 66 | /ex/tamer-wsecho.cc 67 | /ex/tamer-yes 68 | /ex/tamer-yes.cc 69 | 70 | /test/Makefile 71 | /test/Makefile.in 72 | /test/t[0123][0-9] 73 | /test/t[0123][0-9].cc 74 | 75 | /bench/Makefile 76 | /bench/Makefile.in 77 | /bench/b01-asapwto 78 | /bench/b01-asapwto.cc 79 | /bench/b02-string 80 | /bench/b02-string.cc 81 | 82 | /knot/Makefile 83 | /knot/Makefile.in 84 | /knot/cache2.cc 85 | /knot/http.cc 86 | /knot/input.cc 87 | /knot/knot.cc 88 | /knot/knot.tamer 89 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "http-parser"] 2 | path = http-parser 3 | url = https://github.com/nodejs/http-parser 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: c++ 2 | compiler: 3 | - gcc 4 | - clang 5 | addons: 6 | apt: 7 | sources: 8 | - ubuntu-toolchain-r-test 9 | packages: 10 | - gcc-6 11 | - g++-6 12 | before_script: 13 | - if test CC=gcc && which gcc-4.8 >/dev/null 2>&1; then export CC=gcc-4.8 CXX=g++-4.8; fi 14 | - if test CC=gcc && which gcc-4.9 >/dev/null 2>&1; then export CC=gcc-4.9 CXX=g++-4.9; fi 15 | - if test CC=gcc && which gcc-5 >/dev/null 2>&1; then export CC=gcc-5 CXX=g++-5; fi 16 | - if test CC=gcc && which gcc-6 >/dev/null 2>&1; then export CC=gcc-6 CXX=g++-6; fi 17 | - ./bootstrap.sh 18 | script: ./configure && make && make check 19 | sudo: false 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2007, Eddie Kohler 2 | Copyright (c) 2007, Regents of the University of California 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, 10 | this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the University of California, Los Angeles nor the 17 | names of its contributors may be used to endorse or promote products 18 | derived from this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 24 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ## Process this file with automake to produce Makefile.in 2 | AUTOMAKE_OPTIONS = foreign check-news 3 | 4 | EXTRA_DIST = LICENSE 5 | 6 | SUBDIRS = compiler tamer test bench ex doc knot 7 | 8 | compiler tamer test bench ex doc knot: Makefile config.h 9 | cd $@ && $(MAKE) $(AM_MAKEFLAGS) 10 | tamer: compiler 11 | test bench ex knot: compiler tamer 12 | 13 | check: ex test 14 | $(srcdir)/test/testie $(srcdir)/test 15 | 16 | check-%: compiler tamer 17 | cd test && $(MAKE) $(AM_MAKEFLAGS) $* 18 | $(srcdir)/test/testie $(srcdir)/test/$*.testie 19 | 20 | .PHONY: check compiler tamer test bench ex doc knot 21 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | Tamer NEWS 2 | 3 | Version 1.3.0 25.Feb.2010 4 | 5 | * Improve compilability. 6 | 7 | * Add optional helpers to make disk I/O nonblocking. Helper support can be 8 | turned on by configuring with --enable-fd-helper. Disk I/O helper 9 | support by Dero Gharibian. 10 | 11 | * Add asynchronous DNS resolver by Dero Gharibian. 12 | 13 | 14 | Version 1.2.2 16.Aug.2007 15 | 16 | * Fix bugs. 17 | 18 | 19 | Version 1.2.1 5.Jul.2007 20 | 21 | * Change licensing terms to the BSD license. 22 | 23 | 24 | Version 1.2.0 13.Jun.2007 25 | 26 | * Eliminate event cancellation; after experience, it was a bad idea. Now, 27 | when the last reference to an active event is dropped, the event 28 | automatically triggers (but this is considered an error and an error 29 | message is printed). This simplifies a lot of code. (Max disagrees, and 30 | would prefer a dereferenced event to silently disappear; we will see.) 31 | 32 | * event::at_trigger() replaces event::at_cancel() and 33 | event::at_complete(). tamer::unbind() replaces tamer::ignore_slot(). 34 | event::bind_all() replaces event::make_unbound(). 35 | 36 | 37 | Version 1.1.0 5.Jun.2007 38 | 39 | * Remove tamer::fileio and tamer::at_fd_close in favor of a tamer::fd 40 | object with a better interface. 41 | 42 | * Language improvements: Add "twait volatile { }" blocks. Add name 43 | mangling to closure names, allowing tamed overloaded functions. Allow 44 | tvars{} variable initialization with "type var = value". 45 | 46 | * Add support for a libevent back end. When this back end is used, Tamer 47 | functions like tamer::at_fd_read() compile into libevent "struct event"s, 48 | and the Tamer driver is a wrapper for libevent's driver. To use the 49 | Tamer native driver, set the TAMER_NOLIBEVENT environment variable. 50 | 51 | * Add tamer::fun_event(), which wraps a function or function object in an 52 | event. 53 | 54 | * Add event::canceler() and event::at_complete(). 55 | 56 | * Bug fixes in tamer::mutex, tamer::at_time, tamer::with_timeout. 57 | 58 | * Include #defines for version numbers. 59 | 60 | * "make clean" fixes from Henrik Nordstrom. 61 | 62 | 63 | Version 1.0.0 22.May.2007 64 | 65 | * Initial release. 66 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Tamer [![Build Status](https://travis-ci.org/kohler/tamer.svg?branch=master)](https://travis-ci.org/kohler/tamer) 2 | ===== 3 | 4 | Tamer is a C++ language extension and library that simplifies 5 | event-driven programming. Functions in Tamer can block to wait for an 6 | event, then resume computation later. Other functions can continue 7 | while a function is blocked. This is normally hard to code without 8 | closures, and even somewhat annoying in languages that have closures; 9 | Tamer makes it relatively easy. Compared with threaded programs, tamed 10 | programs aren’t much harder to understand, but they avoid most 11 | synchronization and locking issues and generally require less memory. 12 | 13 | Tamer contains a preprocessor that translates Tamer code into 14 | conventional C++ code; libraries for event-driven programming; and 15 | several examples, including a working port of the Knot web server 16 | distributed with the Capriccio threading package. 17 | 18 | If you are building from a source repository (git), you will need 19 | to generate configure scripts. (This is not necessary if you 20 | downloaded a tarball.) Make sure you have the necessary development 21 | packages: flex, bison, automake, and libtool. Then run 22 | `./bootstrap.sh` from the top directory. 23 | 24 | Thereafter installation is standard. Run `./configure`, supplying 25 | any options, then `make install`. Documentation is supplied in manual 26 | page format, and as doxygen comments in the user-facing header files 27 | in "tamer/". After `make install`, try `man 3 tamer`. (Before 28 | installation, try `nroff -man doc/tamer.3 | less`.) 29 | 30 | 31 | Tamer and SFSlite 32 | ----------------- 33 | 34 | Tamer is a lightweight version of the Tame event-driven programming 35 | package distributed as part of SFSlite. For historical reasons, Tame 36 | follows SFS conventions, and requires a wide variety of less than 37 | documented general-purpose classes, including strings, string buffers, 38 | vectors, hash tables, linked lists, and reference counts. Better, or at 39 | least more standard, versions of many of these classes are available as 40 | part of the C++ standard library and the Boost libraries. Additionally, 41 | the Tame abstractions are layered on top of SFSlite's existing "wrap" 42 | callbacks, adding complexity and some overhead. 43 | 44 | Tamer is a freestanding port of the basic Tame abstractions to a 45 | standard C++ environment. Although currently less powerful than Tame and 46 | SFSlite -- for example, Tamer code can block on disk I/O, a problem SFSlite 47 | can solve with RPCs, and SFSlite ships with an asynchronous DNS resolver -- 48 | Tamer is much smaller and lighter weight. It was also designed to be 49 | easier to use. 50 | 51 | If your main concern is code readability, try Tamer. If you really can 52 | never block, or would benefit from built-in RPC support, try Tame. 53 | 54 | 55 | License and Non-Warranty 56 | ------------------------ 57 | 58 | The Tamer libraries and examples are distributed under the BSD license. 59 | See the file "LICENSE", which is described in the source code as "the Tamer 60 | LICENSE file". 61 | 62 | The "tamer" preprocessor, which consists of the source code in the 63 | "compiler" subdirectory, is distributed under the GNU General Public 64 | License, Version 2. See the file "COPYING" in that directory. This means 65 | that any modifications to the compiler are subject to the terms of the GPL. 66 | The preprocessor's output is NOT a "derived work", however, so the tamer 67 | preprocessor may be used to compile software using any licensing terms. 68 | 69 | The "knot.tamer" server in the "knot" directory is derived from the 70 | "knot" server, distributed as part of the Capriccio system. We believe 71 | this server was released under the BSD license. See "knot/README". 72 | 73 | 74 | Bugs and Contributing 75 | --------------------- 76 | 77 | We are happy to accept bug reports, patches, and contributions of code, 78 | for example to improve Tamer's support for nonblocking disk I/O. Send them 79 | to Eddie Kohler at the address below. 80 | 81 | 82 | Authors 83 | ------- 84 | 85 | * Eddie Kohler 86 | http://read.seas.harvard.edu/~kohler/ 87 | * Dero Gharibian 88 | File open/read/write/fstat helper for asynchronous disk I/O; asynchronous 89 | DNS resolver. 90 | * Maxwell Krohn 91 | http://www.okws.org/ 92 | Especially for the original version of the tamer preprocessor and 93 | consultation on the name of the fileio:: namespace. 94 | -------------------------------------------------------------------------------- /bench/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = b01-asapwto b02-string 2 | 3 | b01_asapwto_SOURCES = b01-asapwto.tcc 4 | b02_string_SOURCES = b02-string.tcc 5 | 6 | DRIVER_LIBS = @DRIVER_LIBS@ 7 | MALLOC_LIBS = @MALLOC_LIBS@ 8 | LDADD = ../tamer/libtamer.la $(DRIVER_LIBS) $(MALLOC_LIBS) 9 | 10 | AM_CPPFLAGS = -I$(top_srcdir) -I$(top_builddir) 11 | 12 | if TAMER_SANITIZERS 13 | AM_CXXFLAGS = @SANITIZER_FLAGS@ 14 | AM_LDFLAGS = @SANITIZER_FLAGS@ 15 | endif 16 | 17 | TAMER = ../compiler/tamer 18 | .tcc.cc: 19 | $(TAMER) -o $@ -c $< || (rm $@ && false) 20 | 21 | b01-asapwto.cc: $(srcdir)/b01-asapwto.tcc $(TAMER) 22 | b02-string.cc: $(srcdir)/b02-string.tcc $(TAMER) 23 | 24 | TAMED_CXXFILES = b01-asapwto.cc b02-string.cc 25 | CLEANFILES = $(TAMED_CXXFILES) 26 | .PRECIOUS: $(TAMED_CXXFILES) 27 | -------------------------------------------------------------------------------- /bench/b01-asapwto.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2012, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | int loops = 5000000; 22 | int n; 23 | 24 | tamed void asap(tamer::event<> e) { 25 | tvars { int i, r; } 26 | for (i = 0; i < loops; ++i) 27 | twait { tamer::at_asap(tamer::with_timeout(1, make_event(), r)); } 28 | e.trigger(); 29 | } 30 | 31 | int main(int, char **) { 32 | tamer::initialize(); 33 | tamer::rendezvous<> r; 34 | tamer::event<> e = make_event(r); 35 | asap(e); 36 | while (e) 37 | tamer::once(); 38 | tamer::cleanup(); 39 | } 40 | -------------------------------------------------------------------------------- /bench/b02-string.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2012, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | int loops = 5000000; 24 | 25 | template struct make_random {}; 26 | template <> struct make_random { 27 | int operator()() { 28 | return random(); 29 | } 30 | }; 31 | template <> struct make_random { 32 | std::string operator()() { 33 | return std::to_string(random()); 34 | } 35 | }; 36 | 37 | tamed template void go() { 38 | tvars { 39 | int i; 40 | const int nstorage = 90481, nvalues = 1024; 41 | T values[1024]; 42 | T* storage; 43 | } 44 | { 45 | make_random r; 46 | for (i = 0; i < nvalues; ++i) 47 | values[i] = r(); 48 | storage = new T[nstorage]; 49 | } 50 | twait { 51 | for (i = 0; i < loops; ++i) 52 | tamer::at_asap(tamer::bind(make_event(storage[i % nstorage]), 53 | values[i % nvalues])); 54 | } 55 | delete[] storage; 56 | } 57 | 58 | int main(int, char **) { 59 | tamer::initialize(); 60 | go(); 61 | //go(); 62 | tamer::loop(); 63 | tamer::cleanup(); 64 | } 65 | -------------------------------------------------------------------------------- /bootstrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # check to see if we have the submodules checked out 4 | if [ ! -f http-parser/http_parser.h ]; then 5 | git submodule init 6 | git submodule update 7 | fi 8 | 9 | autoreconf -i -f 10 | echo 11 | echo "Now run ./configure [OPTIONS]." 12 | -------------------------------------------------------------------------------- /compiler/Makefile.am: -------------------------------------------------------------------------------- 1 | ## Process this file with automake to produce Makefile.in 2 | 3 | bin_PROGRAMS = tamer 4 | 5 | noinst_HEADERS = tame.hh parse.hh 6 | 7 | tamer_SOURCES = parse.yy scan.ll processor.cc output.cc tame.cc 8 | tamer_LDADD = $(LDADD) $(LDADD_THR) 9 | 10 | YYFLAGS = -d 11 | 12 | parse.hh: parse.cc 13 | 14 | scan.cc: scan.ll 15 | rm -f $(LEX_OUTPUT_ROOT).c 16 | $(LEX) $(AM_LFLAGS) $(LFLAGS) $(srcdir)/scan.ll \ 17 | && sed -e 's/register //' < $(LEX_OUTPUT_ROOT).c > $(srcdir)/scan.cc \ 18 | && rm -f $(LEX_OUTPUT_ROOT).c 19 | 20 | parse.cc: parse.yy 21 | rm -f y.tab.c y.tab.c2 22 | $(YACC) $(AM_YFLAGS) $(YYFLAGS) $(srcdir)/parse.yy 23 | case "$(YACC)" in \ 24 | *bison*) \ 25 | sed -e 's/union yyalloc/struct yyalloc/g;/^#line/d' \ 26 | -e 's/register //' \ 27 | < y.tab.c > $(srcdir)/parse.cc ; \ 28 | rm -f y.tab.c \ 29 | ;; \ 30 | *) \ 31 | mv -f y.tab.c $(srcdir)/parse.cc \ 32 | ;; \ 33 | esac 34 | if test -f y.tab.h; then \ 35 | if cmp -s y.tab.h $(srcdir)/parse.hh; then \ 36 | rm -f y.tab.h; \ 37 | else \ 38 | mv y.tab.h $(srcdir)/parse.hh; \ 39 | fi; \ 40 | fi 41 | 42 | parse.o: parse.cc tame.hh 43 | # Note: certain versions of bison put __attribute__((unused)) after 44 | # unused goto labels, which doesn't agree well with gcc 3.2.1. 45 | # If you have problems, try the next line instead of the following one. 46 | # $(CXXCOMPILE) $(CXXNOERR) -D'__attribute__(x)=' -c $(srcdir)/parse.cc 47 | $(CXXCOMPILE) $(CXXNOERR) -c $(srcdir)/parse.cc 48 | 49 | scan.o: parse.o scan.cc tame.hh 50 | $(CXXCOMPILE) $(CXXNOERR) -c $(srcdir)/scan.cc 51 | 52 | .PHONY: parseclean 53 | parseclean: 54 | rm -f $(srcdir)/parse.cc $(srcdir)/parse.hh $(srcdir)/scan.cc 55 | 56 | BUILT_SOURCES = parse.cc parse.hh scan.cc 57 | 58 | CLEANFILES = core *.core *~ *.rpo 59 | 60 | EXTRA_DIST = COPYING .cvsignore 61 | MAINTAINERCLEANFILES = parse.hh parse.cc scan.cc 62 | -------------------------------------------------------------------------------- /compiler/output.cc: -------------------------------------------------------------------------------- 1 | #include "tame.hh" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | unsigned count_newlines(const str &s) 10 | { 11 | unsigned n = 0; 12 | for (str::size_type p = 0; (p = s.find('\n', p)) != str::npos; p++) 13 | n++; 14 | return n; 15 | } 16 | 17 | bool 18 | outputter_t::init () 19 | { 20 | if (_outfn.length() && _outfn != "-") { 21 | if ((_fd = open (_outfn.c_str(), O_CREAT|O_WRONLY|O_TRUNC, 0644)) < 0) { 22 | warn << "cannot open file for writing: " << _outfn << "\n"; 23 | return false; 24 | } 25 | } else { 26 | _fd = 1; 27 | } 28 | return true; 29 | } 30 | 31 | void outputter_t::fail_exit() { 32 | if (_fd >= 0 && _outfn.length() && _outfn != "-") 33 | unlink(_outfn.c_str()); 34 | exit(1); 35 | } 36 | 37 | void 38 | outputter_t::start_output () 39 | { 40 | _lineno = 1; 41 | 42 | // switching from NONE to PASSTHROUGH 43 | switch_to_mode (OUTPUT_PASSTHROUGH); 44 | } 45 | 46 | void outputter_t::set_lineno(unsigned lineno, strbuf& b) { 47 | _lineno = lineno; 48 | if (_output_xlate) 49 | export_lineno(b); 50 | } 51 | 52 | void outputter_t::export_lineno(strbuf& b) const { 53 | b << "# " << _lineno << " \"" << _infn << "\"\n"; 54 | } 55 | 56 | void 57 | outputter_t::output_lineno() 58 | { 59 | if (_output_xlate && (_cur_lineno != _lineno || _cur_file != _infn)) { 60 | strbuf b; 61 | if (!_last_char_was_nl) 62 | b << "\n"; 63 | export_lineno(b); 64 | _output_str(b.str(), ""); 65 | _cur_lineno = _lineno; 66 | _cur_file = _infn; 67 | } 68 | } 69 | 70 | void 71 | outputter_H_t::output_str(const str &s) 72 | { 73 | if (_mode == OUTPUT_TREADMILL) { 74 | output_lineno(); 75 | str::size_type p = 0; 76 | bool last_was_line = false; 77 | do { 78 | str::size_type q = s.find('\n', p); 79 | if (q == str::npos) 80 | q = s.length(); 81 | const char* sep = " "; 82 | if (q >= s.length() - 1 || s[q + 1] == '#' || last_was_line) 83 | sep = "\n"; 84 | last_was_line = q < s.length() - 1 && s[q + 1] == '#'; 85 | _output_str(s.substr(p, q - p), sep); 86 | p = q + 1; 87 | } while (p < s.length()); 88 | } else 89 | outputter_t::output_str(s); 90 | } 91 | 92 | void 93 | outputter_t::output_str(const str &s) 94 | { 95 | if (_mode == OUTPUT_TREADMILL) { 96 | output_lineno(); 97 | str::size_type p = 0; 98 | do { 99 | str::size_type q = s.find('\n', p); 100 | if (q == str::npos) 101 | q = s.length(); 102 | output_lineno(); 103 | _output_str(s.substr(p, q - p), "\n"); 104 | p = q + 1; 105 | } while (p < s.length()); 106 | } else { 107 | // we might have set up a defered output_line_number from 108 | // within switch_to_mode; now is the time to do it. 109 | if (s == "\n") 110 | _lineno--; 111 | if (s.length() && _do_output_line_number) { 112 | output_lineno(); 113 | _do_output_line_number = false; 114 | } 115 | _output_str(s, ""); 116 | if (_mode == OUTPUT_PASSTHROUGH) 117 | _lineno += count_newlines(s); 118 | } 119 | } 120 | 121 | void 122 | outputter_t::_output_str(const str &s, const str &sep_str) 123 | { 124 | if (!s.length()) 125 | return; 126 | 127 | _last_output_in_mode = _mode; 128 | 129 | _buf << s; 130 | if (sep_str.length()) { 131 | _buf << sep_str; 132 | _last_char_was_nl = (sep_str[sep_str.length() - 1] == '\n'); 133 | } else 134 | _last_char_was_nl = (s.length() && s[s.length() - 1] == '\n'); 135 | 136 | for (str::size_type p = 0; (p = s.find('\n', p)) != str::npos; p++) 137 | _cur_lineno++; 138 | for (str::size_type p = 0; (p = sep_str.find('\n', p)) != str::npos; p++) 139 | _cur_lineno++; 140 | } 141 | 142 | void 143 | outputter_t::flush() 144 | { 145 | str bufstr = _buf.str(); 146 | const char *x = bufstr.data(), *end = x + bufstr.length(); 147 | while (x < end) { 148 | size_t len = (end - x > 32768 ? 32768 : end - x); 149 | ssize_t w = write(_fd, x, len); 150 | if (w < 0 && errno != EAGAIN && errno != EINTR) { 151 | warn << strerror(errno) << "\n"; 152 | return; 153 | } else if (w > 0) 154 | x += w; 155 | } 156 | } 157 | 158 | outputter_t::~outputter_t () 159 | { 160 | if (_fd >= 0) { 161 | flush (); 162 | close (_fd); 163 | } 164 | } 165 | 166 | output_mode_t 167 | outputter_t::switch_to_mode(output_mode_t m, int nln) 168 | { 169 | output_mode_t old = _mode; 170 | int oln = _lineno; 171 | 172 | if (nln >= 0) 173 | _lineno = nln; 174 | else 175 | nln = oln; 176 | 177 | if (m == OUTPUT_PASSTHROUGH && 178 | (oln != nln || 179 | (old != OUTPUT_NONE && 180 | _last_output_in_mode != OUTPUT_PASSTHROUGH))) { 181 | 182 | // don't call output_line_number() directly, since 183 | // maybe this will be an empty environment 184 | _do_output_line_number = true; 185 | } 186 | _mode = m; 187 | return old; 188 | } 189 | -------------------------------------------------------------------------------- /compiler/tame.cc: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include "tame.hh" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | parse_state_t *state; 11 | bool tamer_debug = false; 12 | outputter_t *outputter; 13 | 14 | std::ostream &warn = std::cerr; 15 | 16 | static void 17 | usage () 18 | { 19 | warn << "usage: tamer [-Lchnv] [-o ] []\n" 20 | << "\n" 21 | << " Flags:\n" 22 | << " -g turn on debugging support\n" 23 | << " -n turn on newlines in autogenerated code\n" 24 | << " -L disable line number translation\n" 25 | << " -h show this screen\n" 26 | << " -v show version number and exit\n" 27 | << "\n" 28 | << " Options:\n" 29 | << " -o specify output file\n" 30 | << " -c compile mode; infer output file name from input file " 31 | << "name\n" 32 | << " -b basename mode; strip off dirs from input file name\n" 33 | << "\n" 34 | << " If no input or output files are specified, then standard in\n" 35 | << " and out are assumed, respectively.\n" 36 | << "\n" 37 | << " Environment Variables:\n" 38 | << " TAME_NO_LINE_NUMBERS equivalent to -L\n" 39 | << " TAME_ADD_NEWLINES equivalent to -n\n" 40 | << " TAME_DEBUG_SOURCE equivalent to -Ln\n" 41 | ; 42 | 43 | exit (1); 44 | } 45 | 46 | static str 47 | ifn2ofn (const str &s) 48 | { 49 | str::size_type rdot = s.rfind('.'); 50 | if (rdot == str::npos || rdot == 0 || rdot == s.length() - 1 51 | || s[rdot - 1] == '/') 52 | return str(); 53 | str base = s.substr(0, rdot); 54 | str ext = s.substr(rdot + 1); 55 | if (ext == "T" || ext == "tC") 56 | return base + ".C"; 57 | else if (ext == "tt" || ext == "tcc") 58 | return base + ".cc"; 59 | else if (ext == "txx" || ext == "tcxx") 60 | return base + ".cxx"; 61 | else if (ext == "tpp" || ext == "tcpp") 62 | return base + ".cpp"; 63 | else if (ext == "thh" || ext == "tth") 64 | return base + ".hh"; 65 | else if (ext == "thxx" || ext == "thx") 66 | return base + ".hxx"; 67 | else if (ext == "thpp" || ext == "thp") 68 | return base + ".hpp"; 69 | else if (ext == "th") 70 | return base + ".h"; 71 | else if (ext == "tH" || ext == "TH") 72 | return base + ".H"; 73 | else 74 | return str(); 75 | } 76 | 77 | static str 78 | basename (const str &s) 79 | { 80 | str::size_type lastslash = s.rfind('/'); 81 | return (lastslash == str::npos ? s : s.substr(lastslash + 1)); 82 | } 83 | 84 | 85 | int 86 | main (int argc, char *argv[]) 87 | { 88 | FILE *ifh = NULL; 89 | int ch; 90 | str outfile; 91 | bool no_line_numbers = false; 92 | bool horiz_mode = true; 93 | bool deps = false; 94 | str ifn, depfile; 95 | bool c_mode (false), b_mode (false); 96 | 97 | while ((ch = getopt (argc, argv, "bghlnDLvdo:c:O:F:")) != -1) 98 | switch (ch) { 99 | case 'g': 100 | tamer_debug = true; 101 | break; 102 | case 'h': 103 | usage(); 104 | break; 105 | case 'l': 106 | std::cout << TAMER_LIBS << "\n"; 107 | exit(0); 108 | break; 109 | case 'n': 110 | horiz_mode = false; 111 | break; 112 | case 'c': 113 | ifn = optarg; 114 | if (!outfile.length()) 115 | outfile = ifn2ofn(ifn); 116 | if (!outfile.length()) { 117 | warn << "-c expects an input file with the .T suffix\n"; 118 | usage (); 119 | } 120 | c_mode = true; 121 | break; 122 | case 'b': 123 | b_mode = true; 124 | break; 125 | case 'L': 126 | no_line_numbers = true; 127 | break; 128 | case 'D': 129 | deps = true; 130 | break; 131 | case 'F': 132 | deps = true; 133 | depfile = optarg; 134 | break; 135 | case 'o': 136 | outfile = optarg; 137 | break; 138 | case 'v': 139 | warn << "tamer\n" 140 | << "compiled " __DATE__ " " __TIME__ "\n" ; 141 | exit (0); 142 | break; 143 | case 'O': 144 | break; 145 | default: 146 | usage (); 147 | break; 148 | } 149 | 150 | if (b_mode) { 151 | if (!c_mode) { 152 | warn << "-b only works when -c is specified\n"; 153 | usage (); 154 | } else { 155 | outfile = basename(outfile); 156 | if (outfile.length() == 0) { 157 | warn << "canont formulate an output file name\n"; 158 | usage (); 159 | } 160 | } 161 | } 162 | 163 | if (getenv ("TAME_DEBUG_SOURCE")) { 164 | no_line_numbers = true; 165 | horiz_mode = false; 166 | } 167 | 168 | if (getenv ("TAME_NO_LINE_NUMBERS")) 169 | no_line_numbers = true; 170 | 171 | if (getenv ("TAME_ADD_NEWLINES")) 172 | horiz_mode = false; 173 | 174 | argc -= optind; 175 | argv += optind; 176 | 177 | if (argc == 1) { 178 | if (ifn.length()) { 179 | warn << "input filename double-specified!\n"; 180 | usage (); 181 | } 182 | ifn = argv[0]; 183 | } 184 | 185 | if (ifn.length() && ifn != "-") { 186 | if (!(ifh = fopen (ifn.c_str (), "r"))) { 187 | warn << "cannot open file: " << ifn << "\n"; 188 | usage (); 189 | } 190 | 191 | // the filename variable is local to scan.ll, which will need 192 | // it to output message messages. It defaults to '(stdin)' 193 | filename = ifn; 194 | 195 | yyin = ifh; 196 | } 197 | 198 | if (deps) { 199 | if (outfile.empty() || ifn.empty() || ifn == "-") { 200 | warn << "-D requires -c or -o\n"; 201 | usage(); 202 | } else if (depfile.empty()) 203 | depfile = outfile + ".d"; 204 | FILE* f = fopen(depfile.c_str(), "w"); 205 | if (!f) { 206 | warn << depfile << ": " << strerror(errno); 207 | exit(1); 208 | } 209 | fprintf(f, "%s: %s\n\n%s:\n", outfile.c_str(), ifn.c_str(), ifn.c_str()); 210 | fclose(f); 211 | } 212 | 213 | state = new parse_state_t (); 214 | 215 | state->set_infile_name (ifn); 216 | bool fl = (ifn.length() && ifn != "-" && !no_line_numbers); 217 | if (horiz_mode) { 218 | outputter = new outputter_H_t (ifn, outfile, fl); 219 | } else { 220 | outputter = new outputter_t (ifn, outfile, fl); 221 | } 222 | if (!outputter->init ()) 223 | exit (1); 224 | 225 | // only on if YYDEBUG is on :( 226 | // yydebug = 1; 227 | 228 | yyparse (); 229 | 230 | if (ifh) { 231 | fclose (ifh); 232 | } 233 | 234 | state->output (outputter); 235 | 236 | // calls close on the outputter fd 237 | delete outputter; 238 | } 239 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | man_MANS = tamer.3 tamer_fd.3 tamer.1 2 | EXTRA_DIST = $(man_MANS) Doxyfile 3 | -------------------------------------------------------------------------------- /doc/tamer.1: -------------------------------------------------------------------------------- 1 | .TH TAMER 1 2007-04-30 Tamer "Tamer Processor Manual" 2 | .ds E \-\-\- 3 | .if t .ds E \(em 4 | .de M 5 | .BR "\\$1" "(\\$2)\\$3" 6 | .. 7 | .SH NAME 8 | tamer \- C++ preprocessor for event-driven programming 9 | .SH SYNOPSIS 10 | .BR tamer " [" \-g "] [" "\-o \fIfile" "] " \fIfile 11 | .br 12 | .BR tamer " [" \-g "] " \-c " \fIfile" 13 | .fi 14 | .SH DESCRIPTION 15 | The 16 | .B tamer 17 | C++ preprocessor reads a source file that uses the 18 | .B Tamer 19 | extensions and generates the corresponding conventional C++. 20 | .LP 21 | The 22 | .B Tamer 23 | programming model is described in more detail at 24 | .M tamer 3 . 25 | ' 26 | .SH OPTIONS 27 | .TP 5 28 | .B \-g 29 | Generate code in debugging mode. Debugging mode tracks the filenames and 30 | line numbers corresponding to important objects at runtime, allowing 31 | .B Tamer 32 | to generate better error messages. 33 | .TP 5 34 | .BI \-o " file" 35 | Places the output C++ source in 36 | .IR file . 37 | .TP 5 38 | .BI \-c 39 | Compilation mode: automatically derives the output filename from the input 40 | filename. For example, a file named 41 | .B ex1.tt 42 | will be compiled into a file named 43 | .BR ex1.cc , 44 | .B ex2.tpp 45 | will be compiled into 46 | .BR ex2.cpp , 47 | and so forth. 48 | ' 49 | .SH BUGS AND LIMITATIONS 50 | .LP 51 | There are several limitations in handling 52 | .BR tamed 53 | class member functions. Do not define a 54 | .B tamed 55 | member function in the class body. Also, 56 | .B tamed 57 | static member function 58 | .I definitions 59 | must use the 60 | .B static 61 | keyword (this is illegal in normal C++). For example, don't say this: 62 | .nf 63 | .sp 64 | class foo { 65 | tamed void memfn() { ... }; 66 | tamed static void staticmemfn(); 67 | }; 68 | tamed void foo::staticmemfn() { ... } 69 | .sp 70 | .fi 71 | Say this: 72 | .nf 73 | .sp 74 | class foo { 75 | tamed void memfn(); 76 | tamed static void staticmemfn(); 77 | }; 78 | tamed void foo::memfn() { ... } 79 | tamed static void foo::staticmemfn() { ... } 80 | .sp 81 | .fi 82 | .LP 83 | There are likely remaining bugs in class member functions and template 84 | functions. 85 | .LP 86 | The 87 | .B tamed 88 | keyword must be the first thing in the function declaration. 89 | .LP 90 | .B Tamer 91 | preprocessing should happen 92 | .I after 93 | the normal C++ preprocessor, but it currently happens before. 94 | ' 95 | .SH AUTHOR 96 | Maxwell Krohn : original Tame version 97 | .br 98 | Eddie Kohler : improvements, port to 99 | .B Tamer 100 | ' 101 | .SH "SEE ALSO" 102 | .M tamer 3 103 | .LP 104 | \*(lqEvents Can Make Sense\*(rq. Maxwell Krohn, Eddie Kohler, and Frans 105 | Kaashoek. In 106 | .I Proc. USENIX 2007 Annual Technical Conference. 107 | Also available at 108 | http://www.cs.ucla.edu/~kohler/pubs/krohn07events.pdf 109 | -------------------------------------------------------------------------------- /doc/tamer.3.md: -------------------------------------------------------------------------------- 1 | tamer(3) - event-driven programming support for C++ 2 | 3 | ## SYNOPSIS 4 | 5 | #include 6 | using namespace tamer; 7 | 8 | class event<> { public: 9 | event(); 10 | operator bool() const; 11 | bool empty() const; 12 | void operator()(); 13 | void trigger(); // synonym for operator()() 14 | void at_trigger(const event<>& e); 15 | event<>& operator+=(event<> e); 16 | } 17 | 18 | template 19 | class event { public: 20 | event(); 21 | operator bool() const; 22 | bool empty() const; 23 | void operator()(T v); 24 | void trigger(T v); 25 | void at_trigger(const event<>& e); 26 | void unblock(); 27 | event<> unblocker() const; 28 | event& operator+=(event e); 29 | } 30 | 31 | tamed void example(event<> done) { 32 | tvars { ... closure variable declarations; ... } 33 | twait { ... at_delay(5, make_event()); ... } 34 | done(); 35 | } 36 | 37 | ## DESCRIPTION 38 | 39 | `Tamer` provides language extensions and libraries that simplify 40 | C++ event-driven programming. This page describes the Tamer 41 | abstractions and some of the user-accessible methods and functions in 42 | the Tamer library. Most Tamer programs will also use the tamer(1) 43 | preprocessor, which converts programs with `tamed` functions into 44 | conventional C++. 45 | 46 | ## OVERVIEW 47 | 48 | Tamer programming uses two main concepts, **events** and **tamed 49 | functions**. An event is an object representing a future occurrence. A 50 | tamed function is a function that can block until one or more events 51 | complete. 52 | 53 | The following tamed function blocks for 5 seconds (during which other 54 | computation can proceed), then prints "Done" to standard output: 55 | 56 | tamed void done_after_5sec(event<> done) { 57 | twait { tamer::at_delay(5, make_event()); } 58 | std::cout << "Done\n"; 59 | done(); 60 | } 61 | 62 | How does this work? 63 | 64 | * The `tamed` keyword marks a function as tamed. 65 | 66 | * The `twait` keyword marks a code region that can block. `twait` can 67 | only appear in tamed functions. 68 | 69 | * The call to `make_event()` creates an `event<>` object bound to 70 | the `twait` region. 71 | 72 | * The call to `tamer::at_delay()` tells the Tamer library to register 73 | a timer that'll go off in 5 seconds. The event is triggered when 74 | the timer expires. Tamer understands several kinds of primitive 75 | occurrence, including file descriptor events, signals, and timers; 76 | users build up more complex occurrences from these primitives. 77 | 78 | * The `twait` region executes as normal until the final right brace. 79 | Then it blocks until all events bound to the region have 80 | triggered. Here, there's one bound event, which will trigger in 5 81 | seconds. 82 | 83 | * When `done_after_5sec` blocks, it appears to return to its caller. 84 | However, its state, arguments, and blocking point are preserved in 85 | a heap **closure**. When the relevant events trigger, the function 86 | will pick up where it left off. 87 | 88 | * After 5 seconds, the event is triggered. This resumes the tamed 89 | function, which prints to standard output. 90 | 91 | * Finally, the tamed function signals its actual completion by 92 | triggering the `done` event, which was passed as an argument. An 93 | event is used to indicate completion because tamed functions 94 | typically return to their callers before they complete. 95 | 96 | ## EVENT VALUES 97 | 98 | Events can pass values when they are triggered. Triggering an 99 | `event<>` simply indicates that the event has happened, but triggering 100 | an `event` will pass a value of type `T` back to the event's 101 | creator. For instance, the following code blocks for 5 seconds, then 102 | triggers the `done` event, passing it the current time as a double: 103 | 104 | tamed void done_after_5sec(event done) { 105 | twait { tamer::at_delay(5, make_event()); } 106 | done(tamer::dnow()); 107 | } 108 | 109 | That might be used in the following context, which tests how long it 110 | takes for a function to unblock: 111 | 112 | tamed unblock_test(event<> done) { 113 | tamed { double unblock_time; } 114 | twait { done_after_5sec(make_event(unblock_time)); } 115 | std::cout << "Unblocked at time " << unblock_time << "\n" 116 | << "It is now " << tamer::dnow() << "\n"; 117 | done(); 118 | } 119 | 120 | How does this work? 121 | 122 | * The `done_after_5sec` tamed function now takes an `event` 123 | argument. To trigger such an event, you must supply a `double`. 124 | 125 | * The `unblock_test` tamed function uses the `tamed` keyword to 126 | mark declarations of **closure variables**, which 127 | are local variables that survive across `twait` regions. Here 128 | there is one such variable, `unblock_time`. 129 | 130 | (Normal local variables are stored on the stack, rather than in 131 | the closure. Their values are reset whenever a tamed function 132 | blocks.) 133 | 134 | * The call to `make_event(unblock_time)` creates an `event` 135 | rather than an `event<>`. This event contains a reference to the 136 | `unblock_time` closure variable. When the event is triggered, the 137 | supplied double value will be stored there. 138 | -------------------------------------------------------------------------------- /doc/tamer_fd.3: -------------------------------------------------------------------------------- 1 | .TH TAMER::FD 3 2007-06-05 Tamer "Tamer Manual" 2 | .ds E \-\-\- 3 | .if t .ds E \(em 4 | .de M 5 | .BR "\\$1" "(\\$2)\\$3" 6 | .. 7 | .SH NAME 8 | tamer_fd \- Tamer file descriptor support 9 | .SH SYNOPSIS 10 | .nf 11 | .B #include 12 | .B using namespace tamer; 13 | .sp 14 | \fBclass fd { public: 15 | fd(); 16 | \&... 17 | } 18 | .fi 19 | .SH DESCRIPTION 20 | The 21 | .B tamer::fd 22 | class wraps file descriptors in a convenient interface for 23 | .M tamer 3 24 | event-based programming. Its methods resemble Unix system calls, but 25 | adapted for Tamer events. 26 | .LP 27 | .B fd 28 | wrappers are reference-counted and may be freely passed as arguments, 29 | copied, assigned, and destroyed. Many 30 | .B fd 31 | wrappers may refer to the same underlying file descriptor. This file 32 | descriptor is closed when the last wrapper to reference it is destroyed. 33 | Alternately, the 34 | .B fd::close() 35 | member function explicitly closes the underlying file descriptor. 36 | .M 37 | When an 38 | .B fd 39 | file descriptor wrapper is closed, any pending 40 | .B tamer::at_fd_read() 41 | and 42 | .B tamer::at_fd_write() 43 | events are triggered, and any pending 44 | .BR tamer::fd::read() , 45 | .BR tamer::fd::write() , 46 | .BR tamer::fd::accept() , 47 | .BR tamer::fd::connect() , 48 | and similar pending 49 | .B fd 50 | methods will terminate, with the 51 | .B \-ECANCELED 52 | error code (or, equivalently, 53 | .BR tamer::outcome::cancel ). 54 | Any 55 | .B fd 56 | methods on a closed file descriptor return the 57 | .B \-EBADF 58 | error code. 59 | .LP 60 | For more information, please see the comments in the 61 | .B 62 | header file, or this Web address: 63 | .nf 64 | http://www.read.cs.ucla.edu/tamer/doxygen/classtamer_1_1fd.html 65 | ' 66 | .SH AUTHOR 67 | Eddie Kohler 68 | .br 69 | Based on joint work on Tame with Maxwell Krohn and Frans 70 | Kaashoek 71 | ' 72 | .SH "SEE ALSO" 73 | .M tamer 3 , 74 | .M tamer 1 75 | .LP 76 | \*(lqEvents Can Make Sense\*(rq. Maxwell Krohn, Eddie Kohler, and Frans 77 | Kaashoek. In 78 | .I Proc. USENIX 2007 Annual Technical Conference. 79 | Also available at 80 | http://www.cs.ucla.edu/~kohler/pubs/krohn07events.pdf 81 | -------------------------------------------------------------------------------- /ex/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = ex6 tamer-yes tamer-echosrv 2 | EXTRA_PROGRAMS = osptracker 3 | 4 | ex6_SOURCES = ex6.tt 5 | ex6_LDADD = ../tamer/libtamer.la $(DRIVER_LIBS) $(MALLOC_LIBS) 6 | 7 | osptracker_SOURCES = osptracker.tcc md5.c md5.h 8 | osptracker_LDADD = ../tamer/libtamer.la $(DRIVER_LIBS) $(MALLOC_LIBS) 9 | 10 | tamer_yes_SOURCES = tamer-yes.tcc 11 | tamer_yes_LDADD = ../tamer/libtamer.la $(DRIVER_LIBS) $(MALLOC_LIBS) 12 | 13 | tamer_echosrv_SOURCES = tamer-echosrv.tcc 14 | tamer_echosrv_LDADD = ../tamer/libtamer.la $(DRIVER_LIBS) $(MALLOC_LIBS) 15 | 16 | tamer_httpd_SOURCES = tamer-httpd.tcc 17 | tamer_httpd_LDADD = ../tamer/libtamer.la $(DRIVER_LIBS) $(MALLOC_LIBS) 18 | 19 | tamer_wsecho_SOURCES = tamer-wsecho.tcc 20 | tamer_wsecho_LDADD = ../tamer/libtamer.la $(DRIVER_LIBS) $(MALLOC_LIBS) 21 | 22 | DRIVER_LIBS = @DRIVER_LIBS@ 23 | MALLOC_LIBS = @MALLOC_LIBS@ 24 | 25 | AM_CPPFLAGS = -I$(top_srcdir) -I$(top_builddir) 26 | 27 | if HTTP_PARSER 28 | noinst_PROGRAMS += tamer-httpd 29 | AM_CPPFLAGS += -I$(top_srcdir)/http-parser 30 | endif 31 | 32 | if TAMER_SANITIZERS 33 | AM_CXXFLAGS = @SANITIZER_FLAGS@ 34 | AM_LDFLAGS = @SANITIZER_FLAGS@ 35 | endif 36 | 37 | if MBEDTLS 38 | noinst_PROGRAMS += tamer-wsecho 39 | endif 40 | 41 | TAMER = ../compiler/tamer 42 | .tt.cc: 43 | $(TAMER) -g -o $@ -c $< || (rm $@ && false) 44 | .tcc.cc: 45 | $(TAMER) -g -o $@ -c $< || (rm $@ && false) 46 | 47 | ex6.cc: $(srcdir)/ex6.tt $(TAMER) 48 | osptracker.cc: $(srcdir)/osptracker.tcc $(TAMER) 49 | tamer-yes.cc: $(srcdir)/tamer-yes.tcc $(TAMER) 50 | tamer-echosrv.cc: $(srcdir)/tamer-echosrv.tcc $(TAMER) 51 | tamer-httpd.cc: $(srcdir)/tamer-httpd.tcc $(TAMER) 52 | tamer-wsecho.cc: $(srcdir)/tamer-wsecho.tcc $(TAMER) 53 | 54 | clean-local: 55 | -rm -f ex6.cc osptracker.cc tamer-yes.cc tamer-echosrv.cc tamer-httpd.cc tamer-wsecho.cc 56 | -------------------------------------------------------------------------------- /ex/ex6.tt: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | #include 3 | 4 | bool run = true; 5 | 6 | void print(tamer::dns::reply p) { 7 | struct in_addr ina; 8 | if (p && *p) { 9 | if (p->name.size()) 10 | printf(":%s:\n", p->name.c_str()); 11 | for (size_t j = 0; j < p->addrs.size(); j++){ 12 | ina.s_addr = p->addrs[j]; 13 | printf(":%s:\n", inet_ntoa(ina)); 14 | } 15 | } else 16 | printf("error reply\n"); 17 | } 18 | 19 | tamed void a() { 20 | tvars { 21 | tamer::dns::reply r1, r2; 22 | struct in_addr addr; 23 | } 24 | 25 | addr.s_addr = inet_addr("64.233.167.99"); 26 | 27 | twait { 28 | tamer::gethostbyname("www.google.com", 0, make_event(r1)); 29 | tamer::gethostbyaddr(&addr, make_event(r2)); 30 | } 31 | 32 | print(r1); 33 | print(r2); 34 | run = false; 35 | } 36 | 37 | int main(int, char **) { 38 | tamer::initialize(); 39 | 40 | a(); 41 | 42 | while (run) 43 | tamer::once(); 44 | } 45 | -------------------------------------------------------------------------------- /ex/md5.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2006-2007 Regents of the University of California 3 | Altered for Click by Eddie Kohler. */ 4 | /* 5 | Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. 6 | 7 | This software is provided 'as-is', without any express or implied 8 | warranty. In no event will the authors be held liable for any damages 9 | arising from the use of this software. 10 | 11 | Permission is granted to anyone to use this software for any purpose, 12 | including commercial applications, and to alter it and redistribute it 13 | freely, subject to the following restrictions: 14 | 15 | 1. The origin of this software must not be misrepresented; you must not 16 | claim that you wrote the original software. If you use this software 17 | in a product, an acknowledgment in the product documentation would be 18 | appreciated but is not required. 19 | 2. Altered source versions must be plainly marked as such, and must not be 20 | misrepresented as being the original software. 21 | 3. This notice may not be removed or altered from any source distribution. 22 | 23 | L. Peter Deutsch 24 | ghost@aladdin.com 25 | 26 | */ 27 | /* 28 | Independent implementation of MD5 (RFC 1321). 29 | 30 | This code implements the MD5 Algorithm defined in RFC 1321, whose 31 | text is available at 32 | http://www.ietf.org/rfc/rfc1321.txt 33 | The code is derived from the text of the RFC, including the test suite 34 | (section A.5) but excluding the rest of Appendix A. It does not include 35 | any code or documentation that is identified in the RFC as being 36 | copyrighted. 37 | 38 | The original and principal author of md5.h is L. Peter Deutsch 39 | . Other authors are noted in the change history 40 | that follows (in reverse chronological order): 41 | 42 | 2002-04-13 lpd Removed support for non-ANSI compilers; removed 43 | references to Ghostscript; clarified derivation from RFC 1321; 44 | now handles byte order either statically or dynamically. 45 | 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 46 | 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); 47 | added conditionalization for C++ compilation from Martin 48 | Purschke . 49 | 1999-05-03 lpd Original version. 50 | */ 51 | 52 | #ifndef CLICK_MD5_H 53 | #define CLICK_MD5_H 54 | #include 55 | 56 | /* 57 | * This package supports both compile-time and run-time determination of CPU 58 | * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be 59 | * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is 60 | * defined as non-zero, the code will be compiled to run only on big-endian 61 | * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to 62 | * run on either big- or little-endian CPUs, but will run slightly less 63 | * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. 64 | */ 65 | 66 | typedef unsigned char md5_byte_t; /* 8-bit byte */ 67 | typedef uint32_t md5_word_t; /* 32-bit word */ 68 | 69 | /* Define the state of the MD5 Algorithm. */ 70 | typedef struct md5_state_s { 71 | md5_word_t count[2]; /* message length in bits, lsw first */ 72 | md5_word_t abcd[4]; /* digest buffer */ 73 | md5_byte_t buf[64]; /* accumulate block */ 74 | } md5_state_t; 75 | 76 | #ifdef __cplusplus 77 | extern "C" 78 | { 79 | #endif 80 | 81 | /* Initialize the algorithm. */ 82 | void md5_init(md5_state_t *pms); 83 | 84 | /* Append a string to the message. */ 85 | void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); 86 | 87 | /* Finish the message and return the digest. */ 88 | #define MD5_DIGEST_SIZE 16 89 | void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); 90 | 91 | /* Finish the message and return the digest in ASCII. DOES NOT write a 92 | terminating NUL character. 93 | If 'allow_at == 0', the digest uses characters [A-Za-z0-9_], and has 94 | length between MD5_TEXT_DIGEST_SIZE and MD5_TEXT_DIGEST_MAX_SIZE. 95 | If 'allow_at != 0', the digest uses characters [A-Za-z0-9_@], and has 96 | length of exactly MD5_TEXT_DIGEST_SIZE. 97 | Returns the number of characters written. Again, this will NOT include 98 | a terminating NUL. */ 99 | #define MD5_TEXT_DIGEST_SIZE 22 /* min len */ 100 | #define MD5_TEXT_DIGEST_MAX_SIZE 26 /* max len if !allow_at */ 101 | int md5_finish_text(md5_state_t *pms, char *text_digest, int allow_at); 102 | 103 | #define md5_free(pms) /* do nothing */ 104 | 105 | #ifdef __cplusplus 106 | } 107 | #endif 108 | 109 | #endif 110 | 111 | -------------------------------------------------------------------------------- /ex/tamer-echosrv.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2012, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | tamed void runone(tamer::fd cfd, double timeout) { 21 | tvars { 22 | char buf[BUFSIZ]; 23 | size_t rpos = 0, nread = 0, nwritten = 0; 24 | tamer::rendezvous r; 25 | tamer::event<> reader, writer; 26 | int x; 27 | } 28 | 29 | if (timeout > 0) 30 | tamer::at_delay(timeout, make_event(r, 1)); 31 | 32 | while (cfd) { 33 | if (rpos < BUFSIZ && !reader) { 34 | reader = make_event(r, 2); 35 | cfd.read_once(buf + rpos, BUFSIZ - rpos, nread, reader); 36 | } 37 | if (rpos > 0 && !writer) { 38 | writer = make_event(r, 3); 39 | cfd.write_once(buf, rpos, nwritten, writer); 40 | } 41 | 42 | twait(r, x); 43 | 44 | if (x == 1) 45 | cfd.close(); 46 | else if (x == 2 && nread) { 47 | rpos += nread; 48 | writer.unblock(); 49 | } else if (x == 3 && nwritten) { 50 | rpos += nread; 51 | memmove(buf, buf + nwritten, rpos - nwritten); 52 | rpos -= nwritten; 53 | nread = 0; 54 | reader.unblock(); 55 | } 56 | } 57 | 58 | r.clear(); 59 | } 60 | 61 | tamed void run(tamer::fd listenfd, double timeout) { 62 | tvars { tamer::fd cfd; }; 63 | if (!listenfd) 64 | fprintf(stderr, "listen: %s\n", strerror(-listenfd.error())); 65 | while (listenfd) { 66 | twait { listenfd.accept(make_event(cfd)); } 67 | runone(cfd, timeout); 68 | } 69 | } 70 | 71 | static void usage() { 72 | fprintf(stderr, "Usage: tamer-echosrv [-p PORT] [-t TIMEOUT]\n"); 73 | } 74 | 75 | int main(int argc, char **argv) { 76 | int opt; 77 | int port = 11111; 78 | double timeout = 0; 79 | while ((opt = getopt(argc, argv, "hp:t:")) != -1) { 80 | switch (opt) { 81 | case 'h': 82 | usage(); 83 | exit(0); 84 | case 'p': 85 | port = strtol(optarg, 0, 0); 86 | break; 87 | case 't': 88 | timeout = strtod(optarg, 0); 89 | break; 90 | case '?': 91 | usage: 92 | usage(); 93 | exit(1); 94 | } 95 | } 96 | 97 | if (optind != argc) 98 | goto usage; 99 | 100 | tamer::initialize(); 101 | run(tamer::tcp_listen(port), timeout); 102 | tamer::loop(); 103 | tamer::cleanup(); 104 | } 105 | -------------------------------------------------------------------------------- /ex/tamer-httpd.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2014, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | tamed void runone(tamer::fd cfd, double delay) { 23 | tvars { 24 | tamer::http_parser hp(HTTP_REQUEST); 25 | tamer::http_message req, res; 26 | std::ostringstream buf; 27 | } 28 | 29 | while (cfd) { 30 | twait { hp.receive(cfd, make_event(req)); } 31 | if (!hp.ok()) 32 | break; 33 | res.clear(); 34 | buf.str(std::string()); 35 | buf << "URL: " << req.url() << "\n"; 36 | for (auto it = req.header_begin(); it != req.header_end(); ++it) 37 | buf << "Header: " << it->name << ": " << it->value << "\n"; 38 | for (auto it = req.query_begin(); it != req.query_end(); ++it) 39 | buf << "Query: " << it->name << ": " << it->value << "\n"; 40 | res.status_code(200).date_header("Date", time(NULL)) 41 | .header("Content-Type", "text/plain") 42 | .body(buf.str()); 43 | twait { hp.send(cfd, res, make_event()); } 44 | if (!hp.should_keep_alive()) 45 | break; 46 | } 47 | } 48 | 49 | tamed void run(tamer::fd listenfd, double delay) { 50 | tvars { tamer::fd cfd; }; 51 | if (!listenfd) 52 | fprintf(stderr, "listen: %s\n", strerror(-listenfd.error())); 53 | while (listenfd) { 54 | twait { listenfd.accept(make_event(cfd)); } 55 | runone(std::move(cfd), delay); 56 | } 57 | } 58 | 59 | static void usage() { 60 | fprintf(stderr, "Usage: tamer-httpd [-p PORT] [-d DELAY]\n"); 61 | } 62 | 63 | int main(int argc, char **argv) { 64 | int opt; 65 | int port = 11111; 66 | double delay = 0; 67 | while ((opt = getopt(argc, argv, "hp:t:")) != -1) { 68 | switch (opt) { 69 | case 'h': 70 | usage(); 71 | exit(0); 72 | case 'p': 73 | port = strtol(optarg, 0, 0); 74 | break; 75 | case 't': 76 | delay = strtod(optarg, 0); 77 | break; 78 | case '?': 79 | usage: 80 | usage(); 81 | exit(1); 82 | } 83 | } 84 | 85 | if (optind != argc) 86 | goto usage; 87 | 88 | tamer::initialize(); 89 | run(tamer::tcp_listen(port), delay); 90 | tamer::loop(); 91 | tamer::cleanup(); 92 | } 93 | -------------------------------------------------------------------------------- /ex/tamer-wsecho.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2016 Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | tamed void runone(tamer::fd cfd, double delay) { 24 | tvars { 25 | tamer::http_parser hp(HTTP_REQUEST); 26 | tamer::http_message req, res; 27 | tamer::websocket_parser wp(HTTP_REQUEST); 28 | tamer::websocket_message wreq, wres; 29 | std::ostringstream buf; 30 | } 31 | 32 | twait { hp.receive(cfd, make_event(req)); } 33 | if (!hp.ok()) 34 | return; 35 | if (!tamer::websocket_handshake::is_request(req)) { 36 | res.status_code(501).date_header("Date", time(NULL)) 37 | .header("Content-Type", "text/plain") 38 | .body("Only WebSocket connections accepted.\n"); 39 | twait { hp.send(cfd, res, make_event()); } 40 | return; 41 | } 42 | 43 | tamer::websocket_handshake::response(res, req); 44 | twait { hp.send(cfd, res, make_event()); } 45 | 46 | while (cfd && wp.ok()) { 47 | twait { wp.receive(cfd, make_event(wreq)); } 48 | if (!wreq) 49 | break; 50 | assert(wreq.opcode() == tamer::WEBSOCKET_TEXT || wreq.opcode() == tamer::WEBSOCKET_BINARY); 51 | wres.opcode(wreq.opcode()).body(wreq.body()); 52 | twait { wp.send(cfd, wres, make_event()); } 53 | } 54 | 55 | // “clean shutdown” suggestion is SHUT_WR, receive until EOF, close. 56 | // we just close. 57 | } 58 | 59 | tamed void run(tamer::fd listenfd, double delay) { 60 | tvars { tamer::fd cfd; }; 61 | if (!listenfd) 62 | fprintf(stderr, "listen: %s\n", strerror(-listenfd.error())); 63 | while (listenfd) { 64 | twait { listenfd.accept(make_event(cfd)); } 65 | runone(std::move(cfd), delay); 66 | } 67 | } 68 | 69 | static void usage() { 70 | fprintf(stderr, "Usage: tamer-wsecho [-p PORT] [-d DELAY]\n"); 71 | } 72 | 73 | int main(int argc, char **argv) { 74 | int opt; 75 | int port = 11111; 76 | double delay = 0; 77 | while ((opt = getopt(argc, argv, "hp:t:")) != -1) { 78 | switch (opt) { 79 | case 'h': 80 | usage(); 81 | exit(0); 82 | case 'p': 83 | port = strtol(optarg, 0, 0); 84 | break; 85 | case 't': 86 | delay = strtod(optarg, 0); 87 | break; 88 | case '?': 89 | usage: 90 | usage(); 91 | exit(1); 92 | } 93 | } 94 | 95 | if (optind != argc) 96 | goto usage; 97 | 98 | tamer::initialize(); 99 | run(tamer::tcp_listen(port), delay); 100 | tamer::loop(); 101 | tamer::cleanup(); 102 | } 103 | -------------------------------------------------------------------------------- /ex/tamer-yes.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2012, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | static sig_atomic_t count = 0; 21 | 22 | void sigint(int) { 23 | fprintf(stderr, "%d\n", count); 24 | exit(1); 25 | } 26 | 27 | tamed void run(tamer::fd fd, std::string s, double rate, unsigned long limit) { 28 | tvars { size_t w; char *xx = 0; int r; } 29 | 30 | while (true) { 31 | // Write a copy of `s` to `fd` 32 | twait { fd.write(s, make_event(r)); } 33 | // Just exit on error 34 | if (r < 0) 35 | exit(0); 36 | 37 | ++count; 38 | if (limit != 0 && (unsigned long) count == limit) 39 | exit(0); 40 | 41 | // If we have a rate limit, obey it. 42 | if (rate > 0) 43 | twait { tamer::at_delay(1 / rate, make_event()); } 44 | } 45 | } 46 | 47 | static void usage() { 48 | fprintf(stderr, "Usage: tamer-yes [-h] [-n] [-r RATE] [-l LIMIT] [STRING]\n"); 49 | } 50 | 51 | int main(int argc, char **argv) { 52 | int opt; 53 | bool newline = true; 54 | double rate = 0; 55 | unsigned long limit = 0; 56 | while ((opt = getopt(argc, argv, "hnr:l:")) != -1) { 57 | switch (opt) { 58 | case 'h': 59 | usage(); 60 | exit(0); 61 | case 'n': 62 | newline = false; 63 | break; 64 | case 'r': 65 | rate = strtod(optarg, 0); 66 | break; 67 | case 'l': 68 | limit = strtoul(optarg, 0, 0); 69 | break; 70 | case '?': 71 | usage: 72 | usage(); 73 | exit(1); 74 | } 75 | } 76 | 77 | std::string s; 78 | if (optind < argc - 1) 79 | goto usage; 80 | else if (optind == argc - 1) 81 | s = argv[optind]; 82 | else 83 | s = "y"; 84 | if (newline) 85 | s += '\n'; 86 | 87 | signal(SIGINT, sigint); 88 | tamer::initialize(); 89 | tamer::fd fd(STDOUT_FILENO); 90 | fd.make_nonblocking(); 91 | run(fd, s, rate, limit); 92 | tamer::loop(); 93 | tamer::cleanup(); 94 | } 95 | -------------------------------------------------------------------------------- /knot/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = knot.tamer 2 | 3 | if TAMER_SANITIZERS 4 | AM_CXXFLAGS = @SANITIZER_FLAGS@ 5 | AM_LDFLAGS = @SANITIZER_FLAGS@ 6 | endif 7 | 8 | knot_tamer_SOURCES = cache2.tt cache2.hh http.tt http.hh httphdrs.h \ 9 | input.tt input.hh knot.tt refptr.hh 10 | knot_tamer_LDADD = ../tamer/libtamer.la @DRIVER_LIBS@ @MALLOC_LIBS@ 11 | 12 | TAMER = ../compiler/tamer 13 | .tt.cc: 14 | $(TAMER) -o $@ -c $< || (rm $@ && false) 15 | 16 | cache2.cc: $(srcdir)/cache2.tt $(TAMER) 17 | http.cc: $(srcdir)/http.tt $(TAMER) 18 | input.cc: $(srcdir)/input.tt $(TAMER) 19 | knot.cc: $(srcdir)/knot.tt $(TAMER) 20 | 21 | AM_CPPFLAGS = -I$(top_srcdir) -I$(top_builddir) 22 | 23 | clean-local: 24 | -rm -f cache2.cc http.cc input.cc knot.cc 25 | -------------------------------------------------------------------------------- /knot/README: -------------------------------------------------------------------------------- 1 | The "knot.tamer" server in this directory was derived by Maxwell Krohn and 2 | Eddie Kohler from the "knot" server distributed as part of Capriccio: 3 | 4 | http://capriccio.cs.berkeley.edu/downloads.html 5 | http://capriccio.cs.berkeley.edu/ 6 | 7 | The contributors to the Capriccio project are: 8 | 9 | Rob von Behren 10 | Jeremy Condit 11 | Feng Zhou 12 | Bill McCloskey 13 | Eric Brewer 14 | George Necula 15 | 16 | We believe Capriccio is distributed under the BSD license. 17 | -------------------------------------------------------------------------------- /knot/cache2.hh: -------------------------------------------------------------------------------- 1 | #ifndef CACHE_HH 2 | #define CACHE_HH 1 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "refptr.hh" 8 | 9 | extern ssize_t g_cache_max; 10 | 11 | struct cache_entry { 12 | 13 | cache_entry(const std::string &n, char *d, size_t len) 14 | : _filename(n), _data(d), _len(len), _refcount(1), _next(0), _prev(0) { 15 | } 16 | 17 | ~cache_entry() { 18 | assert(!_prev && !_next); 19 | delete[] _data; 20 | } 21 | 22 | void use() { 23 | _refcount++; 24 | } 25 | 26 | void unuse() { 27 | if (!--_refcount) 28 | delete this; 29 | } 30 | 31 | char *data() const { 32 | return _data; 33 | } 34 | 35 | size_t size() const { 36 | return _len; 37 | } 38 | 39 | private: 40 | 41 | std::string _filename; 42 | char *_data; 43 | size_t _len; 44 | unsigned _refcount; 45 | cache_entry *_next; 46 | cache_entry *_prev; 47 | 48 | friend class cache; 49 | 50 | }; 51 | 52 | 53 | class cache { public: 54 | 55 | cache(size_t c) 56 | : _load(0), _capacity(c), _head(0), _tail(0) { 57 | } 58 | 59 | void insert(refptr ce); 60 | refptr get(const std::string &fn); 61 | 62 | void empty(); 63 | void remove(cache_entry *); 64 | void evict(); 65 | 66 | private: 67 | 68 | size_t _load; 69 | size_t _capacity; 70 | cache_entry *_head; 71 | cache_entry *_tail; 72 | 73 | }; 74 | 75 | void cache_get(const char *filename, tamer::event > done); 76 | void clear_cache(); 77 | 78 | #endif 79 | -------------------------------------------------------------------------------- /knot/cache2.tt: -------------------------------------------------------------------------------- 1 | // -*-c++-*- 2 | 3 | #include "cache2.hh" 4 | #include "httphdrs.h" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef DEBUG_cache_c 13 | #undef debug 14 | #define debug(...) 15 | #undef tdebug 16 | #define tdebug(...) 17 | #endif 18 | 19 | #define pthread_mutex_lock(...) 20 | #define pthread_mutex_unlock(...) 21 | #define pthread_mutex_init(...) 22 | 23 | 24 | extern int g_use_timer; 25 | extern int g_cache_hits; 26 | extern int g_cache_misses; 27 | 28 | ssize_t g_cache_max = 256 * 1024 * 1024; 29 | 30 | cache *g_cache; 31 | #if LOCKS > 0 32 | tame::lock_table_t *g_locks; 33 | #endif 34 | 35 | cache *the_cache() 36 | { 37 | if (!g_cache) 38 | g_cache = new cache(g_cache_max); 39 | return g_cache; 40 | } 41 | 42 | #if LOCKS > 0 43 | tame::lock_table_t * 44 | locks() 45 | { 46 | if (!g_locks) { 47 | g_locks = new tame::lock_table_t(); 48 | } 49 | return g_locks; 50 | } 51 | #endif 52 | 53 | tamed static void 54 | cache_new(const std::string &filename, tamer::event > ev) 55 | { 56 | tvars { 57 | refptr result; 58 | tamer::fd f; 59 | struct stat fd_stat; 60 | size_t length(0); 61 | int hdrlen(0); 62 | size_t ssrc; 63 | int rc(0); 64 | char *data; 65 | //#if LOCKS > 0 66 | // ptr > lh; 67 | //#endif 68 | } 69 | 70 | //#if LOCKS > 0 71 | // twait { 72 | // locks ()->acquire (&lh, filename, tame::lock_t::EXCLUSIVE, mkevent ()); 73 | // } 74 | //#endif 75 | 76 | twait { 77 | tamer::fd::open(filename.c_str(), O_RDONLY, make_event(f)); 78 | } 79 | 80 | if (f) { 81 | // warn ("open %s\n", filename.cstr ()); 82 | twait { 83 | f.fstat(fd_stat, make_event(rc)); 84 | } 85 | 86 | if (rc < 0) { 87 | perror("fstat"); 88 | // make sure we have a regular file 89 | 90 | } else if (S_ISREG(fd_stat.st_mode)) { 91 | length = fd_stat.st_size; 92 | data = new char[HEADER_200_BUF_SIZE + length]; 93 | 94 | hdrlen = snprintf(data, HEADER_200_BUF_SIZE, 95 | HEADER_200, "text/html", (long) length); 96 | 97 | if (hdrlen < 0 || hdrlen >= HEADER_200_BUF_SIZE) { 98 | fprintf(stderr, "header buffer exceeded\n"); 99 | exit(1); 100 | } 101 | 102 | twait { 103 | f.read(data + hdrlen, length, ssrc, make_event(rc)); 104 | } 105 | 106 | if (rc >= 0) 107 | result = new cache_entry(filename, data, hdrlen + ssrc); 108 | else 109 | fprintf(stderr, "read failed on %s (%s)\n", 110 | filename.c_str(), strerror(-rc)); 111 | 112 | twait { 113 | f.close(make_event(rc)); 114 | } 115 | } 116 | } else { 117 | fprintf(stderr, "warning: error opening file %s: %s\n", filename.c_str(), strerror(-f.error())); 118 | } 119 | ev.trigger(result); 120 | } 121 | 122 | void 123 | clear_cache() 124 | { 125 | the_cache()->empty(); 126 | } 127 | 128 | tamed void 129 | cache_get(const char *filename, tamer::event > ev) 130 | { 131 | tvars { 132 | refptr result; 133 | } 134 | result = the_cache()->get(filename); 135 | 136 | if (result.value() != NULL) { 137 | g_cache_hits++; 138 | } else { 139 | g_cache_misses++; 140 | } 141 | 142 | if (result.value() == NULL) { 143 | debug("file [%s] not in cache; adding\n", filename); 144 | 145 | twait { 146 | cache_new(filename, make_event(result)); 147 | } 148 | 149 | if (result.value() != NULL) { 150 | the_cache()->insert(result); 151 | } 152 | } else { 153 | debug("file [%s] in cache\n", filename); 154 | } 155 | ev.trigger(result); 156 | } 157 | 158 | void 159 | cache::insert(refptr e) 160 | { 161 | assert(!e->_next && !e->_prev); 162 | 163 | for (cache_entry *ee = _head; ee; ee = ee->_next) 164 | if (e->_filename == ee->_filename) { 165 | remove(ee); 166 | break; 167 | } 168 | 169 | _load += e->size(); 170 | e->_next = _head; 171 | if (_head) 172 | _head->_prev = e.value(); 173 | _head = e.value(); 174 | if (!_tail) 175 | _tail = e.value(); 176 | e->use(); 177 | 178 | evict(); 179 | } 180 | 181 | refptr 182 | cache::get(const std::string &fn) 183 | { 184 | for (cache_entry *e = _head; e; e = e->_next) 185 | if (fn == e->_filename) 186 | return e; 187 | return NULL; 188 | } 189 | 190 | void 191 | cache::remove(cache_entry *e) 192 | { 193 | _load -= e->size(); 194 | if (e->_prev) 195 | e->_prev->_next = e->_next; 196 | else 197 | _head = e->_next; 198 | if (e->_next) 199 | e->_next->_prev = e->_prev; 200 | else 201 | _tail = e->_prev; 202 | e->_next = e->_prev = 0; 203 | e->unuse(); 204 | } 205 | 206 | void 207 | cache::evict() 208 | { 209 | while (_load > _capacity && _head) 210 | remove(_head); 211 | } 212 | 213 | void 214 | cache::empty() 215 | { 216 | while (_head) 217 | remove(_head); 218 | } 219 | 220 | ////////////////////////////////////////////////// 221 | // Set the emacs indentation offset 222 | // Local Variables: *** 223 | // c-basic-offset:4 *** 224 | // End: *** 225 | ////////////////////////////////////////////////// 226 | -------------------------------------------------------------------------------- /knot/http.hh: -------------------------------------------------------------------------------- 1 | #ifndef HTTP_H 2 | #define HTTP_H 3 | 4 | #include "input.hh" 5 | #include 6 | 7 | 8 | typedef enum 9 | { 10 | HTTP_VERSION_1_0, 11 | HTTP_VERSION_1_1, 12 | } http_version; 13 | 14 | 15 | struct http_request 16 | { 17 | char url[80]; 18 | http_version version; 19 | int socket; 20 | int closed; 21 | }; 22 | 23 | void http_init(http_request *req, int socket); 24 | 25 | void http_parse(http_request *req, tamer::event ev); 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /knot/http.tt: -------------------------------------------------------------------------------- 1 | // -*-c++-*- 2 | #include 3 | #include 4 | 5 | #include "http.hh" 6 | 7 | #ifndef DEBUG_http_c 8 | #undef debug 9 | #define debug(...) 10 | #undef tdebug 11 | #define tdebug(...) 12 | #endif 13 | 14 | 15 | #define STR_METHOD_GET "GET" 16 | #define STR_VERSION_1_0 "HTTP/1.0" 17 | #define STR_VERSION_1_1 "HTTP/1.1" 18 | 19 | void 20 | http_init(http_request *request, int socket) 21 | { 22 | request->url[0] = 0; 23 | request->version = HTTP_VERSION_1_0; 24 | request->closed = 0; 25 | request->socket = socket; 26 | } 27 | 28 | tamed void 29 | http_parse(http_request *request, tamer::event ev) 30 | { 31 | tvars { 32 | int result (0); 33 | int done (0); 34 | input_state state; 35 | char *line; 36 | } 37 | 38 | input_init(&state, request->socket); 39 | 40 | request->url[0] = 0; 41 | request->version = HTTP_VERSION_1_0; 42 | 43 | while (!done) 44 | { 45 | twait { input_get_line(&state, make_event(line)); } 46 | 47 | if (line == NULL) 48 | { 49 | request->closed = 1; 50 | result = 0; 51 | done = 1; 52 | } 53 | else if (line[0] == 0) 54 | { 55 | result = (request->url[0] != 0); 56 | done = 1; 57 | } 58 | else if (request->url[0] == 0) 59 | { 60 | char *method; 61 | char *url; 62 | char *protocol; 63 | http_version version = HTTP_VERSION_1_0; 64 | int valid = 0; 65 | 66 | method = line; 67 | url = strchr(line, ' '); 68 | 69 | if (url != NULL) 70 | { 71 | *url++ = 0; 72 | protocol = strchr(url, ' '); 73 | 74 | if (protocol != NULL) 75 | { 76 | *protocol++ = 0; 77 | 78 | if (strcmp(method, STR_METHOD_GET) == 0) 79 | { 80 | if (strcmp(protocol, STR_VERSION_1_1) == 0) 81 | { 82 | version = HTTP_VERSION_1_1; 83 | valid = 1; 84 | } 85 | else if (strcmp(protocol, STR_VERSION_1_0) == 0) 86 | { 87 | version = HTTP_VERSION_1_0; 88 | valid = 1; 89 | } 90 | } 91 | } 92 | } 93 | 94 | if (valid) 95 | { 96 | url -= 1; 97 | 98 | assert(line <= url); 99 | url[0] = '.'; 100 | 101 | // save the URL. This is necessary b/c the get_line() 102 | // function returns a pointer into it's internal 103 | // buffer. 104 | assert(strlen(url) < sizeof(request->url)); 105 | strcpy(request->url, url); 106 | assert(request->url[0] == '.'); 107 | 108 | request->version = version; 109 | } 110 | else 111 | { 112 | result = 0; 113 | done = 1; 114 | } 115 | } 116 | else 117 | { 118 | // parse other headers... 119 | } 120 | } 121 | 122 | ev.trigger(result); 123 | } 124 | 125 | 126 | ////////////////////////////////////////////////// 127 | // Set the emacs indentation offset 128 | // Local Variables: *** 129 | // c-basic-offset:4 *** 130 | // End: *** 131 | ////////////////////////////////////////////////// 132 | -------------------------------------------------------------------------------- /knot/httphdrs.h: -------------------------------------------------------------------------------- 1 | #ifndef HTTPHDRS_H 2 | #define HTTPHDRS_H 3 | 4 | #define HEADER_200_BUF_SIZE 128 5 | #define HEADER_200 ("HTTP/1.1 200 OK\r\n" \ 6 | "Content-Type: %s\r\n" \ 7 | "Content-Length: %ld\r\n" \ 8 | "\r\n") 9 | 10 | #define HEADER_404 ("HTTP/1.1 404 Not Found\r\n" \ 11 | "Connection: close\r\n") 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /knot/input.hh: -------------------------------------------------------------------------------- 1 | #ifndef INPUT_H 2 | #define INPUT_H 3 | 4 | #include 5 | 6 | #define INPUT_MAX_BUF 511 7 | 8 | typedef struct input_state input_state; 9 | struct input_state 10 | { 11 | char buf[INPUT_MAX_BUF + 1]; 12 | 13 | int used; 14 | int valid; 15 | 16 | int socket; 17 | }; 18 | 19 | void input_init(input_state *state, int socket); 20 | 21 | void input_get_line(input_state *state, tamer::event ev); 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /knot/input.tt: -------------------------------------------------------------------------------- 1 | // -*-c++-*- 2 | #include 3 | #include 4 | #include 5 | 6 | #include "input.hh" 7 | 8 | 9 | #ifndef DEBUG_input_c 10 | #undef debug 11 | #define debug(...) 12 | #undef tdebug 13 | #define tdebug(...) 14 | #endif 15 | 16 | void 17 | input_init(input_state *state, int socket) 18 | { 19 | assert(state != NULL); 20 | 21 | state->used = 0; 22 | state->valid = 0; 23 | 24 | state->socket = socket; 25 | } 26 | 27 | tamed void 28 | input_get_line(input_state *state, tamer::event ev) 29 | { 30 | tvars { 31 | char *result (NULL); 32 | int done (0); 33 | char *start; 34 | char *newline; 35 | char *empty; 36 | int n; 37 | } 38 | 39 | while (!done) 40 | { 41 | 42 | // brief sanity check 43 | assert(0 <= state->used); 44 | assert(state->used <= state->valid); 45 | assert(state->valid <= INPUT_MAX_BUF); 46 | 47 | // make sure there's a null at the end of the string to search 48 | state->buf[state->valid] = 0; 49 | 50 | // look for a newline 51 | start = &state->buf[state->used]; 52 | newline = strstr(start, "\r\n"); 53 | 54 | if (newline != NULL) 55 | { 56 | // newline was found; return a ptr to the beginning of the line, 57 | // with null termination at the newline 58 | *newline = 0; 59 | result = start; 60 | done = 1; 61 | 62 | // updated used 63 | state->used = newline - state->buf + 2; 64 | 65 | // if there's no more valid data in the buffers, reset 'em 66 | if (state->used == state->valid) 67 | { 68 | state->used = 0; 69 | state->valid = 0; 70 | } 71 | } 72 | else if (state->valid < INPUT_MAX_BUF) 73 | { 74 | // there's still room to read data--fill it up. 75 | empty = &state->buf[state->valid]; 76 | 77 | twait { 78 | tamer::at_fd_read(state->socket, make_event()); 79 | } 80 | n = read (state->socket, empty, INPUT_MAX_BUF - state->valid); 81 | 82 | if (n <= 0) 83 | { 84 | // on error or eof, we're done 85 | result = NULL; 86 | done = 1; 87 | } 88 | else 89 | { 90 | // we got more data, so loop again to look for a newline 91 | state->valid += n; 92 | } 93 | } 94 | else if (state->used > 0) 95 | { 96 | // move the unused data to the beginning of the buffer 97 | memmove( &state->buf[0], &state->buf[state->used], state->valid - state->used ); 98 | state->valid -= state->used; 99 | state->used = 0; 100 | } 101 | else 102 | { 103 | // state->used == 0 && state->valid == INPUT_MAX_BUF, 104 | // so the entire buffer is full of valid, unused data. 105 | // there's no newline in this data, though, so we bail. 106 | result = NULL; 107 | done = 1; 108 | } 109 | } 110 | 111 | ev.trigger (result); 112 | } 113 | 114 | 115 | 116 | ////////////////////////////////////////////////// 117 | // Set the emacs indentation offset 118 | // Local Variables: *** 119 | // c-basic-offset:4 *** 120 | // End: *** 121 | ////////////////////////////////////////////////// 122 | -------------------------------------------------------------------------------- /knot/refptr.hh: -------------------------------------------------------------------------------- 1 | #ifndef REFPTR_HH 2 | #define REFPTR_HH 1 3 | 4 | template class refptr { public: 5 | 6 | refptr() 7 | : _t(0) { 8 | } 9 | 10 | refptr(T *t) 11 | : _t(t) { 12 | if (_t) 13 | _t->use(); 14 | } 15 | 16 | refptr(const refptr &r) 17 | : _t(r._t) { 18 | if (_t) 19 | _t->use(); 20 | } 21 | 22 | ~refptr() { 23 | if (_t) 24 | _t->unuse(); 25 | } 26 | 27 | T *operator->() const { 28 | return _t; 29 | } 30 | 31 | T *value() const { 32 | return _t; 33 | } 34 | 35 | refptr &operator=(const refptr &r) { 36 | if (r._t) 37 | r._t->use(); 38 | if (_t) 39 | _t->unuse(); 40 | _t = r._t; 41 | return *this; 42 | } 43 | 44 | refptr &operator=(T *t) { 45 | if (_t && _t != t) 46 | _t->unuse(); 47 | _t = t; 48 | return *this; 49 | } 50 | 51 | private: 52 | 53 | T *_t; 54 | 55 | }; 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /tamer/Makefile.am: -------------------------------------------------------------------------------- 1 | pkgconfigdir = ${libdir}/pkgconfig 2 | pkgconfig_DATA = tamer.pc 3 | 4 | bin_PROGRAMS = 5 | 6 | lib_LTLIBRARIES = libtamer.la 7 | libtamer_la_SOURCES = \ 8 | adapter.hh \ 9 | bufferedio.hh bufferedio.tcc \ 10 | channel.hh \ 11 | driver.hh \ 12 | dinternal.hh dinternal.cc \ 13 | dlibev.cc \ 14 | dlibevent.cc \ 15 | dtamer.cc \ 16 | dsignal.cc \ 17 | event.hh \ 18 | fd.hh fd.tcc \ 19 | dns.hh dns.tt \ 20 | lock.hh lock.tcc \ 21 | ref.hh \ 22 | rendezvous.hh \ 23 | tamer.hh \ 24 | xadapter.hh xadapter.cc \ 25 | xbase.hh xbase.cc \ 26 | xdriver.hh \ 27 | xevent.hh 28 | pkginclude_HEADERS = \ 29 | adapter.hh \ 30 | autoconf.h \ 31 | bufferedio.hh \ 32 | channel.hh \ 33 | driver.hh \ 34 | event.hh \ 35 | fd.hh \ 36 | dns.hh \ 37 | lock.hh \ 38 | ref.hh \ 39 | rendezvous.hh \ 40 | tamer.hh \ 41 | xadapter.hh \ 42 | xbase.hh \ 43 | xdriver.hh 44 | 45 | tamerfdh_SOURCES = fdhelp.cc 46 | 47 | EXTRA_DIST = autoconf.h.in \ 48 | tamer.pc.in 49 | 50 | AM_CPPFLAGS = -I$(top_srcdir) -I$(top_builddir) 51 | TAMER = ../compiler/tamer 52 | 53 | if HTTP_PARSER 54 | libtamer_la_SOURCES += http_parser.c http.tcc http.hh 55 | AM_CPPFLAGS += -I$(top_srcdir)/http-parser 56 | pkginclude_HEADERS += $(top_srcdir)/http-parser/http_parser.h 57 | if TAMER_DEBUG 58 | AM_CPPFLAGS += -DHTTP_PARSER_STRICT=1 59 | else 60 | AM_CPPFLAGS += -DHTTP_PARSER_STRICT=0 61 | endif 62 | endif 63 | 64 | if TAMER_SANITIZERS 65 | AM_CXXFLAGS = @SANITIZER_FLAGS@ 66 | AM_LDFLAGS = @SANITIZER_FLAGS@ 67 | endif 68 | 69 | if MBEDTLS 70 | libtamer_la_SOURCES += websocket.tcc websocket.hh 71 | endif 72 | 73 | if FDHELPER 74 | libtamer_la_SOURCES += fdhmsg.hh fdhmsg.cc fdh.hh fdh.tt 75 | bin_PROGRAMS += tamerfdh 76 | endif 77 | 78 | .tt.cc: 79 | $(TAMER) -g -o $@ -c $< || (rm $@ && false) 80 | .tcc.cc: 81 | $(TAMER) -g -o $@ -c $< || (rm $@ && false) 82 | 83 | fd.cc: $(TAMER) fd.tcc 84 | fdh.cc: $(TAMER) fdh.tt 85 | dns.cc: $(TAMER) dns.tt 86 | lock.cc: $(TAMER) lock.tcc 87 | bufferedio.cc: $(TAMER) bufferedio.tcc 88 | http.cc: $(TAMER) http.tcc 89 | websocket.cc: $(TAMER) websocket.tcc 90 | 91 | clean-local: 92 | -rm -f lock.cc fd.cc fdh.cc dns.cc bufferedio.cc http.cc websocket.cc 93 | -------------------------------------------------------------------------------- /tamer/autoconf.h.in: -------------------------------------------------------------------------------- 1 | #ifndef TAMER_AUTOCONF_H 2 | #define TAMER_AUTOCONF_H 1 3 | /* Copyright (c) 2012-2023, Eddie Kohler 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a 6 | * copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, subject to the conditions 8 | * listed in the Tamer LICENSE file. These conditions include: you must 9 | * preserve this copyright notice, and you cannot mention the copyright 10 | * holders in advertising related to the Software without their permission. 11 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 12 | * notice is a summary of the Tamer LICENSE file; the license in that file is 13 | * legally binding. 14 | */ 15 | 16 | #ifndef TAMER_DEBUG 17 | /* Define to include more debugging assertions. */ 18 | #undef TAMER_DEBUG 19 | #endif 20 | 21 | #ifndef TAMER_DEBUG_LEVEL 22 | /* Define level of debugging assertions to include. */ 23 | #undef TAMER_DEBUG_LEVEL 24 | #endif 25 | 26 | #ifndef TAMER_NOTRACE 27 | /* Define to disable event tracing. */ 28 | #undef TAMER_NOTRACE 29 | #endif 30 | 31 | #ifndef TAMER_HTTP_PARSER 32 | /* Define if http_parser is included. */ 33 | #undef TAMER_HTTP_PARSER 34 | #endif 35 | 36 | #if __GNUC__ 37 | # define TAMER_GCCVERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) 38 | #else 39 | # define TAMER_GCCVERSION 0 40 | #endif 41 | #if __clang__ 42 | # define TAMER_CLANGVERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) 43 | #else 44 | # define TAMER_CLANGVERSION 0 45 | #endif 46 | 47 | #if __cplusplus >= 201103L || __GXX_EXPERIMENTAL_CXX0X__ 48 | #if !defined(TAMER_HAVE_CXX_CONSTEXPR) && \ 49 | (TAMER_CLANGVERSION >= 30100 || TAMER_GCCVERSION >= 40600) 50 | /* Define if the C++ compiler understands constexpr. */ 51 | #define TAMER_HAVE_CXX_CONSTEXPR 1 52 | #endif 53 | 54 | #if !defined(TAMER_HAVE_CXX_NOEXCEPT) && \ 55 | (TAMER_CLANGVERSION >= 30000 || TAMER_GCCVERSION >= 40600) 56 | /* Define if the C++ compiler understands noexcept. */ 57 | #define TAMER_HAVE_CXX_NOEXCEPT 1 58 | #endif 59 | 60 | #if !defined(TAMER_HAVE_CXX_LAMBDAS) && \ 61 | (TAMER_CLANGVERSION >= 30100 || TAMER_GCCVERSION >= 40500) 62 | /* Define if the C++ compiler understands lambdas. */ 63 | #define TAMER_HAVE_CXX_LAMBDAS 1 64 | #endif 65 | 66 | #if !defined(TAMER_HAVE_CXX_RVALUE_REFERENCES) && \ 67 | (TAMER_CLANGVERSION >= 20900 || TAMER_GCCVERSION >= 40300) 68 | /* Define if the C++ compiler understands rvalue references. */ 69 | #define TAMER_HAVE_CXX_RVALUE_REFERENCES 1 70 | #endif 71 | 72 | #if !defined(TAMER_HAVE_CXX_STATIC_ASSERT) && \ 73 | (TAMER_CLANGVERSION >= 20900 || TAMER_GCCVERSION >= 40300) 74 | /* Define if the C++ compiler understands static_assert. */ 75 | #define TAMER_HAVE_CXX_STATIC_ASSERT 1 76 | #endif 77 | 78 | #if !defined(TAMER_HAVE_CXX_TEMPLATE_ALIAS) && \ 79 | (TAMER_CLANGVERSION >= 30000 || TAMER_GCCVERSION >= 40700) 80 | /* Define if the C++ compiler understands template alias. */ 81 | #define TAMER_HAVE_CXX_TEMPLATE_ALIAS 1 82 | #endif 83 | 84 | #if !defined(TAMER_HAVE_CXX_VARIADIC_TEMPLATES) && \ 85 | (TAMER_CLANGVERSION >= 20900 || TAMER_GCCVERSION >= 40300) 86 | /* Define if the C++ compiler understands variadic templates. */ 87 | #define TAMER_HAVE_CXX_VARIADIC_TEMPLATES 1 88 | #endif 89 | #endif 90 | 91 | #if TAMER_HAVE_CXX_NOEXCEPT 92 | #define TAMER_NOEXCEPT noexcept 93 | #else 94 | #define TAMER_NOEXCEPT 95 | #define noexcept 96 | #endif 97 | 98 | #if TAMER_HAVE_CXX_CONSTEXPR 99 | #define TAMER_CONSTEXPR constexpr 100 | #else 101 | #define TAMER_CONSTEXPR 102 | #define constexpr 103 | #endif 104 | 105 | #if TAMER_HAVE_CXX_RVALUE_REFERENCES 106 | #define TAMER_MOVEARG(t, ...) t, ## __VA_ARGS__ && 107 | #define TAMER_MOVE(v) std::move(v) 108 | #else 109 | #define TAMER_MOVEARG(t, ...) t, ## __VA_ARGS__ 110 | #define TAMER_MOVE(v) v 111 | #endif 112 | 113 | #if !defined(TAMER_HAVE_PREEVENT) && TAMER_HAVE_CXX_RVALUE_REFERENCES 114 | #define TAMER_HAVE_PREEVENT 1 115 | #endif 116 | 117 | #if __GNUC__ 118 | #define TAMER_CLOSUREVARATTR __attribute__((unused)) 119 | #define TAMER_DEPRECATEDATTR __attribute__((deprecated)) 120 | #else 121 | #define TAMER_CLOSUREVARATTR 122 | #define TAMER_DEPRECATEDATTR 123 | #endif 124 | 125 | #if __GNUC__ && !TAMER_NOTRACE 126 | #define TAMER_MAKE_ANNOTATED_EVENT(r, ...) make_annotated_event(__FILE__, __LINE__, r, ## __VA_ARGS__) 127 | #define TAMER_MAKE_FN_ANNOTATED_EVENT(r, ...) make_annotated_event(__PRETTY_FUNCTION__, 0, r, ## __VA_ARGS__) 128 | #elif !TAMER_NOTRACE 129 | #define TAMER_MAKE_ANNOTATED_EVENT(r, ...) make_annotated_event(__FILE__, __LINE__, r, ## __VA_ARGS__) 130 | #define TAMER_MAKE_FN_ANNOTATED_EVENT(r, ...) make_annotated_event(__FILE__, __LINE__, r, ## __VA_ARGS__) 131 | #else 132 | #define TAMER_MAKE_ANNOTATED_EVENT make_event 133 | #define TAMER_MAKE_FN_ANNOTATED_EVENT make_event 134 | #endif 135 | 136 | #if TAMER_DEBUG 137 | #define TAMER_DEBUG_ASSERT(x) assert(x) 138 | #else 139 | #define TAMER_DEBUG_ASSERT(x) 140 | #endif 141 | 142 | #if !TAMER_NOTRACE 143 | #define TAMER_IFTRACE(...) __VA_ARGS__ 144 | #define TAMER_IFNOTRACE(...) 145 | #define TAMER_IFTRACE_ELSE(x, y) x 146 | #else 147 | #define TAMER_IFTRACE(...) 148 | #define TAMER_IFNOTRACE(...) __VA_ARGS__ 149 | #define TAMER_IFTRACE_ELSE(x, y) y 150 | #endif 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /tamer/bufferedio.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAMER_BUFFEREDIO_HH 2 | #define TAMER_BUFFEREDIO_HH 1 3 | /* Copyright (c) 2007-2015, Eddie Kohler 4 | * Copyright (c) 2007, Regents of the University of California 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a 7 | * copy of this software and associated documentation files (the "Software"), 8 | * to deal in the Software without restriction, subject to the conditions 9 | * listed in the Tamer LICENSE file. These conditions include: you must 10 | * preserve this copyright notice, and you cannot mention the copyright 11 | * holders in advertising related to the Software without their permission. 12 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 13 | * notice is a summary of the Tamer LICENSE file; the license in that file is 14 | * legally binding. 15 | */ 16 | #include 17 | #include 18 | #include 19 | namespace tamer { 20 | 21 | class buffer { 22 | public: 23 | buffer(size_t initial_capacity = 1024); 24 | ~buffer(); 25 | 26 | std::string str() const; // debugging 27 | 28 | void fill_until(fd f, char c, size_t max_size, size_t& out_size, event done); 29 | void take_until(fd f, char c, size_t max_size, std::string& str, event done); 30 | 31 | private: 32 | char* buf_; 33 | size_t size_; 34 | size_t head_ = 0; 35 | size_t tail_ = 0; 36 | 37 | ssize_t fill_more(fd f, const event& done); 38 | 39 | class closure__fill_until__2fdckRkQi_; 40 | void fill_until(closure__fill_until__2fdckRkQi_&); 41 | class closure__take_until__2fdckRSsQi_; 42 | void take_until(closure__take_until__2fdckRSsQi_&); 43 | }; 44 | 45 | } 46 | #endif /* TAMER_BUFFEREDIO_HH */ 47 | -------------------------------------------------------------------------------- /tamer/bufferedio.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2007-2015, Eddie Kohler 3 | * Copyright (c) 2007, Regents of the University of California 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a 6 | * copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, subject to the conditions 8 | * listed in the Tamer LICENSE file. These conditions include: you must 9 | * preserve this copyright notice, and you cannot mention the copyright 10 | * holders in advertising related to the Software without their permission. 11 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 12 | * notice is a summary of the Tamer LICENSE file; the license in that file is 13 | * legally binding. 14 | */ 15 | #include "config.h" 16 | #include 17 | #include 18 | 19 | namespace tamer { 20 | 21 | buffer::buffer(size_t initial_capacity) { 22 | for (size_ = 1; size_ < initial_capacity && size_ != 0; size_ *= 2) { 23 | } 24 | if (size_ == 0) { 25 | size_ = 1024; 26 | } 27 | buf_ = new char[size_]; 28 | } 29 | 30 | buffer::~buffer() { 31 | delete[] buf_; 32 | } 33 | 34 | std::string buffer::str() const { 35 | size_t headpos = head_ & (size_ - 1); 36 | size_t tailpos = tail_ & (size_ - 1); 37 | if (headpos <= tailpos) { 38 | return std::string(buf_ + headpos, tailpos - headpos); 39 | } else { 40 | std::string s(buf_ + headpos, size_ - headpos); 41 | s.append(buf_, tailpos); 42 | return s; 43 | } 44 | } 45 | 46 | ssize_t buffer::fill_more(fd f, const event& done) { 47 | if (!done || !f) { 48 | return -ECANCELED; 49 | } 50 | if (head_ + size_ == tail_) { 51 | char *new_buf = new char[size_ * 2]; 52 | if (!new_buf) { 53 | return -ENOMEM; 54 | } 55 | size_t off = head_ & (size_ - 1); 56 | memcpy(new_buf, buf_ + off, size_ - off); 57 | memcpy(new_buf + size_ - off, buf_, off); 58 | head_ = 0; 59 | tail_ = size_; 60 | delete[] buf_; 61 | buf_ = new_buf; 62 | size_ = 2 * size_; 63 | } 64 | 65 | ssize_t amt; 66 | size_t headpos = head_ & (size_ - 1); 67 | size_t tailpos = tail_ & (size_ - 1); 68 | if (headpos <= tailpos) { 69 | amt = ::read(f.fdnum(), buf_ + tailpos, size_ - tailpos); 70 | } else { 71 | amt = ::read(f.fdnum(), buf_ + tailpos, headpos - tailpos); 72 | } 73 | 74 | if (amt != (ssize_t) -1) { 75 | return amt; 76 | } else if (errno == EAGAIN || errno == EWOULDBLOCK) { 77 | return -EAGAIN; 78 | } else { 79 | return -errno; 80 | } 81 | } 82 | 83 | tamed void buffer::fill_until(fd f, char c, size_t max_size, size_t &out_size, 84 | event done) { 85 | tamed { 86 | int ret = -ECANCELED; 87 | size_t pos = this->head_; 88 | ssize_t amt; 89 | } 90 | 91 | out_size = 0; 92 | 93 | while (done) { 94 | for (; pos != tail_ && pos != head_ + max_size; ++pos) { 95 | if (buf_[pos & (size_ - 1)] == c) { 96 | ++pos; 97 | ret = 0; 98 | goto done; 99 | } 100 | } 101 | 102 | if (pos == head_ + max_size || !f) { 103 | ret = -E2BIG; 104 | break; 105 | } 106 | 107 | assert(pos == tail_); 108 | amt = fill_more(f, done); 109 | pos = tail_; 110 | if (amt == -EAGAIN) { 111 | twait volatile { tamer::at_fd_read(f.fdnum(), make_event()); } 112 | } else if (amt <= 0) { 113 | ret = (amt == 0 ? tamer::outcome::closed : amt); 114 | break; 115 | } else { 116 | tail_ += amt; 117 | } 118 | } 119 | 120 | done: 121 | out_size = pos - head_; 122 | done.trigger(ret); 123 | } 124 | 125 | tamed void buffer::take_until(fd f, char c, size_t max_size, std::string& str, 126 | event done) { 127 | tamed { 128 | size_t size; 129 | int ret; 130 | rendezvous<> r; 131 | } 132 | 133 | str = std::string(); 134 | 135 | done.at_trigger(make_event(r)); 136 | fill_until(f, c, max_size, size, make_event(r, ret)); 137 | twait(r); 138 | 139 | if (done && ret == 0) { 140 | assert(size > 0); 141 | size_t a = head_ & (size_ - 1); 142 | size_t b = (head_ + size) & (size_ - 1); 143 | if (a < b) { 144 | str = std::string(buf_ + a, buf_ + b); 145 | } else { 146 | str = std::string(buf_ + a, buf_ + size_) + std::string(buf_, buf_ + b); 147 | } 148 | head_ += size; 149 | } 150 | done.trigger(ret); 151 | } 152 | 153 | } 154 | -------------------------------------------------------------------------------- /tamer/channel.hh: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | #ifndef TAMER_CHANNEL_HH 3 | #define TAMER_CHANNEL_HH 1 4 | #include 5 | #include 6 | namespace tamer { 7 | 8 | template 9 | class channel { 10 | public: 11 | typedef typename std::deque::size_type size_type; 12 | 13 | inline channel(); 14 | 15 | inline size_type size() const; 16 | inline bool empty() const; 17 | 18 | inline size_type wait_size() const; 19 | inline bool wait_empty() const; 20 | 21 | inline void push_front(T x); 22 | inline void push_back(T x); 23 | inline void pop_front(tamer::event e); 24 | inline void pop_back(tamer::event e); 25 | 26 | private: 27 | std::deque q_; 28 | std::deque > waitq_; 29 | 30 | }; 31 | 32 | template 33 | inline channel::channel() { 34 | } 35 | 36 | template 37 | inline typename channel::size_type channel::size() const { 38 | return q_.size(); 39 | } 40 | 41 | template 42 | inline bool channel::empty() const { 43 | return q_.empty(); 44 | } 45 | 46 | template 47 | inline typename channel::size_type channel::wait_size() const { 48 | return waitq_.size(); 49 | } 50 | 51 | template 52 | inline bool channel::wait_empty() const { 53 | return waitq_.empty(); 54 | } 55 | 56 | template 57 | inline void channel::push_front(T x) { 58 | while (!waitq_.empty() && !waitq_.front()) 59 | waitq_.pop_front(); 60 | if (!waitq_.empty()) { 61 | waitq_.front()(TAMER_MOVE(x)); 62 | waitq_.pop_front(); 63 | } else 64 | q_.push_front(TAMER_MOVE(x)); 65 | } 66 | 67 | template 68 | inline void channel::push_back(T x) { 69 | while (!waitq_.empty() && !waitq_.front()) 70 | waitq_.pop_front(); 71 | if (!waitq_.empty()) { 72 | waitq_.front()(TAMER_MOVE(x)); 73 | waitq_.pop_front(); 74 | } else 75 | q_.push_back(TAMER_MOVE(x)); 76 | } 77 | 78 | template 79 | inline void channel::pop_front(tamer::event e) { 80 | if (!q_.empty()) { 81 | e(q_.front()); 82 | q_.pop_front(); 83 | } else 84 | waitq_.push_back(TAMER_MOVE(e)); 85 | } 86 | 87 | template 88 | inline void channel::pop_back(tamer::event e) { 89 | if (!q_.empty()) { 90 | e(q_.back()); 91 | q_.pop_back(); 92 | } else 93 | waitq_.push_back(TAMER_MOVE(e)); 94 | } 95 | 96 | } 97 | #endif 98 | -------------------------------------------------------------------------------- /tamer/driver.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAMER_DRIVER_HH 2 | #define TAMER_DRIVER_HH 1 3 | /* Copyright (c) 2007-2015, Eddie Kohler 4 | * Copyright (c) 2007, Regents of the University of California 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a 7 | * copy of this software and associated documentation files (the "Software"), 8 | * to deal in the Software without restriction, subject to the conditions 9 | * listed in the Tamer LICENSE file. These conditions include: you must 10 | * preserve this copyright notice, and you cannot mention the copyright 11 | * holders in advertising related to the Software without their permission. 12 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 13 | * notice is a summary of the Tamer LICENSE file; the license in that file is 14 | * legally binding. 15 | */ 16 | #include 17 | namespace tamer { 18 | 19 | /** @file 20 | * @brief Functions for registering primitive events and managing the event 21 | * loop. 22 | */ 23 | 24 | enum init_flags { 25 | init_tamer = 1, 26 | init_libevent = 2, 27 | init_libev = 4, 28 | init_sigpipe = 0x1000, 29 | init_strict = 0x2000, 30 | init_no_epoll = 0x4000 31 | }; 32 | 33 | /** @brief Initialize the Tamer event loop. 34 | * @param flags Initialization flags, taken from init_flags. 35 | * 36 | * Call tamer::initialize at least once before registering any primitive 37 | * Tamer events. The @a flags argument may contain one or more 38 | * constants to request a specific driver (init_tamer, init_libevent, or 39 | * init_libev). 40 | * 41 | * By default Tamer ignores the SIGPIPE signal, which is generally what 42 | * event-driven programs want. Add init_sigpipe to @a flags if you 43 | * want to turn off this behavior. 44 | */ 45 | bool initialize(int flags = 0); 46 | 47 | /** @brief Clean up the Tamer event loop. 48 | * 49 | * Delete the driver. Should not be called unless all Tamer objects are 50 | * deleted. 51 | */ 52 | void cleanup(); 53 | 54 | enum time_type_t { 55 | time_normal, 56 | time_virtual 57 | }; 58 | 59 | void set_time_type(time_type_t tt); 60 | 61 | /** @brief Return a recent snapshot of the current time. */ 62 | inline const timeval& recent() { 63 | if (tamerpriv::need_recent) { 64 | tamerpriv::recent = now(); 65 | tamerpriv::need_recent = false; 66 | } 67 | return tamerpriv::recent; 68 | } 69 | 70 | /** @brief Sets Tamer's current time to the current timestamp. 71 | */ 72 | inline void set_recent() { 73 | tamerpriv::need_recent = true; 74 | } 75 | 76 | /** @brief Translate a time to a double. */ 77 | inline double dtime(const timeval tv) { 78 | return tv.tv_sec + tv.tv_usec / 1000000.; 79 | } 80 | 81 | /** @brief Return the current time as a double. */ 82 | inline double dnow() { 83 | return dtime(now()); 84 | } 85 | 86 | /** @brief Return a recent snapshot of the current time as a double. */ 87 | inline double drecent() { 88 | return dtime(recent()); 89 | } 90 | 91 | /** @brief Run driver loop according to @a flags. */ 92 | inline void loop(loop_flags flags) { 93 | driver::main->loop(flags); 94 | } 95 | 96 | /** @brief Run driver loop indefinitely. */ 97 | inline void loop() { 98 | driver::main->loop(loop_forever); 99 | } 100 | 101 | /** @brief Run driver loop once. */ 102 | inline void once() { 103 | driver::main->loop(loop_once); 104 | } 105 | 106 | /** @brief Exit the current driver loop. */ 107 | inline void break_loop() { 108 | driver::main->break_loop(); 109 | } 110 | 111 | /** @brief Register event for file descriptor readability. 112 | * @param fd File descriptor. 113 | * @param e Event. 114 | * 115 | * Triggers @a e when @a fd becomes readable. Cancels @a e when @a fd is 116 | * closed. 117 | */ 118 | inline void at_fd_read(int fd, event<> e) { 119 | driver::main->at_fd(fd, fd_read, e); 120 | } 121 | 122 | inline void at_fd_read(int fd, event e) { 123 | driver::main->at_fd(fd, fd_read, e); 124 | } 125 | 126 | /** @brief Register event for file descriptor writability. 127 | * @param fd File descriptor. 128 | * @param e Event. 129 | * 130 | * Triggers @a e when @a fd becomes writable. Cancels @a e when @a fd is 131 | * closed. 132 | */ 133 | inline void at_fd_write(int fd, event<> e) { 134 | driver::main->at_fd(fd, fd_write, e); 135 | } 136 | 137 | inline void at_fd_write(int fd, event e) { 138 | driver::main->at_fd(fd, fd_write, e); 139 | } 140 | 141 | /** @brief Register event for file descriptor shutdown. 142 | * @param fd File descriptor. 143 | * @param e Event. 144 | * 145 | * Triggers @a e when @a fd is shut down or closed. 146 | */ 147 | inline void at_fd_shutdown(int fd, event<> e) { 148 | driver::main->at_fd(fd, fd_hangup, e); 149 | } 150 | 151 | /** @brief Register event for a given time. 152 | * @param expiry Time. 153 | * @param e Event. 154 | * 155 | * Triggers @a e at timestamp @a expiry, or soon afterwards. 156 | */ 157 | inline void at_time(const timeval &expiry, event<> e, bool bg = false) { 158 | driver::main->at_time(expiry, e, bg); 159 | } 160 | 161 | /** @overload */ 162 | inline void at_time(double expiry, event<> e, bool bg = false) { 163 | driver::main->at_time(expiry, e, bg); 164 | } 165 | 166 | /** @brief Register event for a given delay. 167 | * @param delay Delay time. 168 | * @param e Event. 169 | * 170 | * Triggers @a e when @a delay seconds have elapsed since @c recent(), or 171 | * soon afterwards. 172 | */ 173 | inline void at_delay(const timeval &delay, event<> e, bool bg = false) { 174 | driver::main->at_delay(delay, e, bg); 175 | } 176 | 177 | /** @brief Register event for a given delay. 178 | * @param delay Delay time. 179 | * @param e Event. 180 | * 181 | * Triggers @a e when @a delay seconds have elapsed since @c recent(), or 182 | * soon afterwards. 183 | */ 184 | inline void at_delay(double delay, event<> e, bool bg = false) { 185 | driver::main->at_delay(delay, e, bg); 186 | } 187 | 188 | /** @brief Register event for a given delay. 189 | * @param delay Delay time. 190 | * @param e Event. 191 | * 192 | * Triggers @a e when @a delay seconds have elapsed since @c recent(), or 193 | * soon afterwards. 194 | */ 195 | inline void at_delay_sec(int delay, event<> e, bool bg = false) { 196 | driver::main->at_delay_sec(delay, e, bg); 197 | } 198 | 199 | /** @brief Register event for a given delay. 200 | * @param delay Delay time in milliseconds. 201 | * @param e Event. 202 | * 203 | * Triggers @a e when @a delay milliseconds have elapsed since @c recent(), 204 | * or soon afterwards. 205 | */ 206 | inline void at_delay_msec(int delay, event<> e, bool bg = false) { 207 | driver::main->at_delay_msec(delay, e, bg); 208 | } 209 | 210 | /** @brief Register event for a given delay. 211 | * @param delay Delay time in microseconds. 212 | * @param e Event. 213 | * 214 | * Triggers @a e when @a delay microseconds have elapsed since @c recent(), 215 | * or soon afterwards. 216 | */ 217 | inline void at_delay_usec(int delay, event<> e, bool bg = false) { 218 | driver::main->at_delay_usec(delay, e, bg); 219 | } 220 | 221 | /** @brief Register event for signal occurrence. 222 | * @param signo Signal number. 223 | * @param e Event. 224 | * 225 | * Triggers @a e soon after @a signo is received. The signal @a signo 226 | * is blocked while @a e is triggered and unblocked afterwards. 227 | */ 228 | inline void at_signal(int signo, event<> e) { 229 | driver::at_signal(signo, e); 230 | } 231 | 232 | /** @brief Register event to trigger soon. 233 | * @param e Event. 234 | * 235 | * Triggers @a e the next time through the driver loop. 236 | */ 237 | inline void at_asap(event<> e) { 238 | driver::main->at_asap(e); 239 | } 240 | 241 | /** @brief Register event to trigger before Tamer blocks. 242 | * @param e Event. 243 | * 244 | * Triggers @a e (and runs its closure) before the next blocking point. 245 | */ 246 | inline void at_preblock(event<> e) { 247 | driver::main->at_preblock(e); 248 | } 249 | 250 | namespace tamerpriv { extern time_type_t time_type; } 251 | } // namespace tamer 252 | #endif /* TAMER_DRIVER_HH */ 253 | -------------------------------------------------------------------------------- /tamer/dsignal.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2007-2015, Eddie Kohler 2 | * Copyright (c) 2007, Regents of the University of California 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | namespace tamer { 22 | 23 | volatile sig_atomic_t driver::sig_any_active; 24 | int driver::sig_pipe[2] = { -1, -1 }; 25 | unsigned driver::sig_nforeground = 0; 26 | unsigned driver::sig_ntotal = 0; 27 | 28 | extern "C" { typedef void (*tamer_sighandler)(int); } 29 | static int tamer_sigaction(int signo, tamer_sighandler handler) 30 | { 31 | struct sigaction sa; 32 | sa.sa_handler = handler; 33 | sigemptyset(&sa.sa_mask); 34 | sa.sa_flags = 0; 35 | return sigaction(signo, &sa, 0); 36 | } 37 | 38 | namespace { 39 | class sigcancel_rendezvous : public tamerpriv::functional_rendezvous, 40 | public one_argument_rendezvous_tag { public: 41 | sigcancel_rendezvous() 42 | : functional_rendezvous(hook) { 43 | } 44 | inline uintptr_t make_rid(int sig) TAMER_NOEXCEPT { 45 | assert(sig >= 0 && sig < 2*NSIG); 46 | return sig; 47 | } 48 | static void hook(tamerpriv::functional_rendezvous *fr, 49 | tamerpriv::simple_event *e, bool values) TAMER_NOEXCEPT; 50 | }; 51 | 52 | sigcancel_rendezvous sigcancelr; 53 | volatile sig_atomic_t sig_active[NSIG]; 54 | event<> sig_handlers[NSIG]; 55 | sigset_t sig_dispatching; 56 | 57 | void sigcancel_rendezvous::hook(tamerpriv::functional_rendezvous *, 58 | tamerpriv::simple_event *e, bool) TAMER_NOEXCEPT { 59 | uintptr_t rid = e->rid(); 60 | int signo = rid >> 1; 61 | if (!sig_handlers[signo] && sigismember(&sig_dispatching, signo) == 0) 62 | tamer_sigaction(signo, SIG_DFL); 63 | if (rid & 1) 64 | --driver::sig_nforeground; 65 | --driver::sig_ntotal; 66 | } 67 | } // namespace 68 | 69 | 70 | extern "C" { 71 | static void tamer_signal_handler(int signo) { 72 | driver::sig_any_active = sig_active[signo] = 1; 73 | // ensure select wakes up 74 | if (driver::sig_pipe[1] >= 0) { 75 | int save_errno = errno; 76 | ssize_t r = write(driver::sig_pipe[1], "", 1); 77 | (void) r; // don't care if the write fails 78 | errno = save_errno; 79 | } 80 | } 81 | } 82 | 83 | 84 | void driver::at_signal(int signo, event<> trigger, signal_flags flags) 85 | { 86 | assert(signo >= 0 && signo < NSIG); 87 | 88 | if (sig_pipe[0] < 0 && pipe(sig_pipe) >= 0) { 89 | fcntl(sig_pipe[0], F_SETFL, O_NONBLOCK); 90 | fcntl(sig_pipe[1], F_SETFL, O_NONBLOCK); 91 | fcntl(sig_pipe[0], F_SETFD, FD_CLOEXEC); 92 | fcntl(sig_pipe[1], F_SETFD, FD_CLOEXEC); 93 | sigemptyset(&sig_dispatching); 94 | } 95 | 96 | if (!trigger) // special case forces creation of signal pipe 97 | return; 98 | 99 | bool foreground = (flags & signal_background) == 0; 100 | trigger.at_trigger(make_event(sigcancelr, (signo << 1) + foreground)); 101 | sig_nforeground += foreground; 102 | sig_ntotal += 1; 103 | 104 | sig_handlers[signo] += std::move(trigger); 105 | if (sigismember(&sig_dispatching, signo) == 0) 106 | tamer_sigaction(signo, tamer_signal_handler); 107 | } 108 | 109 | 110 | void driver::dispatch_signals() 111 | { 112 | sig_any_active = 0; 113 | 114 | // kill crap data written to pipe 115 | char crap[64]; 116 | while (read(sig_pipe[0], crap, 64) > 0) 117 | /* do nothing */; 118 | 119 | // find and block signals that have happened 120 | for (int signo = 0; signo < NSIG; ++signo) 121 | if (sig_active[signo]) 122 | sigaddset(&sig_dispatching, signo); 123 | sigprocmask(SIG_BLOCK, &sig_dispatching, 0); 124 | 125 | // trigger those signals 126 | for (int signo = 0; signo < NSIG; ++signo) 127 | if (sigismember(&sig_dispatching, signo) > 0) { 128 | sig_active[signo] = 0; 129 | sig_handlers[signo].trigger(); 130 | } 131 | 132 | // run closures activated by signals (plus maybe some others) 133 | run_unblocked(); 134 | 135 | // reset signal handlers if appropriate 136 | for (int signo = 0; signo < NSIG; ++signo) 137 | if (sigismember(&sig_dispatching, signo) > 0 138 | && !sig_handlers[signo]) 139 | tamer_sigaction(signo, SIG_DFL); 140 | 141 | // now that the signal responders have potentially reinstalled signal 142 | // handlers, unblock the signals 143 | sigprocmask(SIG_UNBLOCK, &sig_dispatching, 0); 144 | sigemptyset(&sig_dispatching); 145 | } 146 | 147 | } // namespace tamer 148 | -------------------------------------------------------------------------------- /tamer/fdh.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAMER_FDH_HH 2 | #define TAMER_FDH_HH 1 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | namespace tamer { 14 | 15 | class fdhelper { public: 16 | 17 | fdhelper() 18 | : _p(new fdhimp) { 19 | } 20 | 21 | void open(const std::string &fname, int flags, mode_t mode, 22 | const event &fd) { 23 | _p->open(fname, flags, mode, fd); 24 | } 25 | void fstat(int fd, struct stat &stat_out, const event &done) { 26 | _p->fstat(fd, stat_out, done); 27 | } 28 | void read(int fd, void *buf, size_t size, size_t &nread, const event &done) { 29 | _p->read(fd, buf, size, nread, done); 30 | } 31 | void write(int fd, const void *buf, size_t size, size_t &nwritten, const event &done) { 32 | _p->write(fd, buf, size, nwritten, done); 33 | } 34 | 35 | private: 36 | 37 | struct fdh { 38 | union { 39 | fdh_msg msg; 40 | char buf[PATH_MAX + FDH_MSG_SIZE]; 41 | } _u; 42 | pid_t _pid; 43 | fd _fd; 44 | 45 | fdh(); 46 | bool ok() const { 47 | return _pid > 0 && _fd; 48 | } 49 | 50 | inline void send(int fd, size_t size, const event &done) { 51 | _fd.sendmsg(_u.buf, size, fd, done); 52 | } 53 | void recv(int *fd, size_t size, event done); 54 | 55 | class closure__recv__PikQi_; void recv(closure__recv__PikQi_ &); 56 | }; 57 | 58 | struct fdhimp : public enable_ref_ptr { 59 | int _min; 60 | int _count; 61 | int _max; 62 | 63 | std::list _helpers; 64 | std::list _ready; 65 | std::list > _waiting; 66 | 67 | fdhimp(); 68 | ~fdhimp(); 69 | 70 | void get(event done); 71 | void put(fdh *h) { 72 | _ready.push_back(h); 73 | if (_waiting.size()) { 74 | _waiting.front().trigger(); 75 | _waiting.pop_front(); 76 | } 77 | } 78 | 79 | void open(std::string fname, int flags, mode_t mode, event fd); 80 | void fstat(int fd, struct stat &stat_out, event done); 81 | void read(int fd, void *buf, size_t size, size_t &nread, event done); 82 | void write(int fd, const void *buf, size_t size, size_t &nwritten, event done); 83 | 84 | class closure__get__QP3fdh_; void get(closure__get__QP3fdh_ &); 85 | class closure__open__Ssi6mode_tQi_; void open(closure__open__Ssi6mode_tQi_ &); 86 | class closure__fstat__iR4statQi_; void fstat(closure__fstat__iR4statQi_ &); 87 | class closure__read__iPvkRkQi_; void read(closure__read__iPvkRkQi_ &); 88 | class closure__write__iPKvkRkQi_; void write(closure__write__iPKvkRkQi_ &); 89 | }; 90 | 91 | ref_ptr _p; 92 | 93 | }; 94 | 95 | } 96 | #endif /* TAMER_FDH_HH */ 97 | -------------------------------------------------------------------------------- /tamer/fdh.tt: -------------------------------------------------------------------------------- 1 | /* -*- mode: c++ -*- */ 2 | #include "config.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define TAMER_HELPER_PATH PACKAGE_BIN_DIR "/tamerfdh" 14 | //TODO any way to do this better? the explicit "/tamerfdh" looks bad 15 | 16 | static char crapbuf[2048]; 17 | 18 | namespace tamer { 19 | 20 | fdhelper::fdhimp::fdhimp() 21 | : _min(4), _max(6) 22 | { 23 | for (int i = 0; i < _min; i++) { 24 | fdh *x = new fdh; 25 | if (x->ok()) { 26 | _helpers.push_back(x); 27 | _ready.push_back(x); 28 | } else 29 | delete x; 30 | } 31 | _count = _ready.size(); 32 | assert(_count > 0); 33 | } 34 | 35 | fdhelper::fdhimp::~fdhimp() 36 | { 37 | while (_helpers.size()) { 38 | fdh *h = _helpers.front(); 39 | _helpers.pop_front(); 40 | delete h; 41 | } 42 | } 43 | 44 | tamed void fdhelper::fdhimp::get(event done) 45 | { 46 | while (!_ready.size() || _waiting.size()) { 47 | twait { 48 | _waiting.push_back(make_event()); 49 | } 50 | } 51 | fdh *h = _ready.front(); 52 | _ready.pop_front(); 53 | done.trigger(h); 54 | } 55 | 56 | 57 | fdhelper::fdh::fdh() 58 | { 59 | int socks[2]; 60 | 61 | if (::socketpair(AF_UNIX, SOCK_STREAM, 0, socks) < 0) 62 | return; 63 | 64 | _pid = ::fork(); 65 | if (_pid < 0) { 66 | ::close(socks[0]); 67 | ::close(socks[1]); 68 | return; 69 | } else if (_pid == 0) { 70 | ::close(socks[0]); 71 | if (::dup2(socks[1], 0) < 0) 72 | goto child_err; 73 | if (::execv(TAMER_HELPER_PATH, NULL) < 0) 74 | goto child_err; 75 | child_err: 76 | ::close(socks[1]); 77 | exit(0); 78 | } 79 | 80 | ::close(socks[1]); 81 | fd::make_nonblocking(socks[0]); 82 | _fd = fd(socks[0]); 83 | } 84 | 85 | tamed void fdhelper::fdh::recv(int *fd, size_t size, event done) 86 | { 87 | tvars { 88 | int amt; 89 | } 90 | 91 | while (done) { 92 | amt = ::fdh_recv(_fd.fdnum(), fd, _u.buf, size); 93 | if (amt > 0) 94 | break; 95 | else if (amt == 0) 96 | continue; 97 | else if (errno == EAGAIN || errno == EWOULDBLOCK) 98 | twait { tamer::at_fd_read(_fd.fdnum(), make_event()); } 99 | else if (errno != EINTR) { 100 | perror("fdh: open: recv"); 101 | done.trigger(-errno); 102 | return; 103 | } 104 | } 105 | 106 | done.trigger(0); 107 | } 108 | 109 | tamed void fdhelper::fdhimp::open(std::string fname, int flags, mode_t mode, event done) 110 | { 111 | tvars { 112 | passive_ref_ptr hold(this); 113 | fdh *h; 114 | int r, fresult; 115 | } 116 | 117 | twait { get(make_event(h)); } 118 | 119 | h->_u.msg.query.req = FDH_OPEN; 120 | h->_u.msg.query.flags = flags; 121 | h->_u.msg.query.mode = mode; 122 | strcpy(&h->_u.buf[FDH_MSG_SIZE], fname.c_str()); 123 | 124 | twait { 125 | h->send(-1, FDH_MSG_SIZE + fname.length() + 1, make_event(r)); 126 | } 127 | if (r < 0) 128 | goto release; 129 | twait { 130 | h->recv(&fresult, FDH_MSG_SIZE, make_event(r)); 131 | } 132 | if (r >= 0 && h->_u.msg.reply.err) 133 | r = -h->_u.msg.reply.err; 134 | 135 | release: 136 | done.trigger(r >= 0 ? fresult : r); 137 | put(h); 138 | } 139 | 140 | tamed void fdhelper::fdhimp::fstat(int fd, struct stat &stat_out, event done) 141 | { 142 | tvars { 143 | passive_ref_ptr hold(this); 144 | fdh *h; 145 | int r, fresult; 146 | } 147 | 148 | twait { get(make_event(h)); } 149 | 150 | h->_u.msg.query.req = FDH_STAT; 151 | twait { 152 | h->send(fd, FDH_MSG_SIZE, make_event(r)); 153 | } 154 | if (r < 0) 155 | goto release; 156 | twait { 157 | h->recv(0, FDH_MSG_SIZE + sizeof(struct stat), make_event(r)); 158 | } 159 | if (r >= 0 && h->_u.msg.reply.err) 160 | r = -h->_u.msg.reply.err; 161 | if (r >= 0) 162 | memcpy(&stat_out, &h->_u.buf[FDH_MSG_SIZE], sizeof(struct stat)); 163 | 164 | release: 165 | done.trigger(r >= 0 ? 0 : r); 166 | put(h); 167 | } 168 | 169 | tamed void fdhelper::fdhimp::read(int read_fd, void *buf, size_t size, size_t &nread, event done) 170 | { 171 | tvars { 172 | passive_ref_ptr hold(this); 173 | fdh *h; 174 | int r; 175 | size_t pos = 0; 176 | size_t amt; 177 | } 178 | 179 | nread = 0; 180 | twait { get(make_event(h)); } 181 | 182 | h->_u.msg.query.req = FDH_READ; 183 | h->_u.msg.query.size = size; 184 | twait { 185 | h->send(read_fd, FDH_MSG_SIZE, make_event(r)); 186 | } 187 | if (r < 0) { 188 | done.trigger(r); 189 | goto release; 190 | } 191 | 192 | while (pos < size && h->_fd && done && r >= 0) { 193 | twait { 194 | h->_fd.read_once(static_cast(buf) + pos, size - pos, amt, make_event(r)); 195 | } 196 | pos += amt; 197 | nread = pos; 198 | if (amt == 0) 199 | break; 200 | } 201 | 202 | done.trigger(r >= 0 ? 0 : r); 203 | 204 | // must read the rest of the file data lest the fd get out of sync 205 | twait { 206 | h->_fd.read(crapbuf, size - pos > sizeof(crapbuf) ? sizeof(crapbuf) : size - pos, make_event(r)); 207 | } 208 | 209 | release: 210 | put(h); 211 | } 212 | 213 | tamed void fdhelper::fdhimp::write(int write_fd, const void *buf, size_t size, size_t &nwritten, event done) 214 | { 215 | tvars { 216 | passive_ref_ptr hold(this); 217 | fdh *h; 218 | int r; 219 | size_t pos = 0; 220 | size_t amt; 221 | } 222 | 223 | nwritten = 0; 224 | twait { get(make_event(h)); } 225 | 226 | h->_u.msg.query.req = FDH_WRITE; 227 | h->_u.msg.query.size = size; 228 | twait { 229 | h->send(write_fd, FDH_MSG_SIZE, make_event(r)); 230 | } 231 | if (r < 0) { 232 | done.trigger(r); 233 | goto release; 234 | } 235 | 236 | while (pos < size && h->_fd && done && r >= 0) { 237 | twait { 238 | h->_fd.write_once(static_cast(buf) + pos, size - pos, amt, make_event(r)); 239 | } 240 | pos += amt; 241 | nwritten = pos; 242 | if (amt == 0) 243 | break; 244 | } 245 | 246 | done.trigger(r >= 0 ? 0 : r); 247 | 248 | // must write the correct amount of data lest the fd get out of sync 249 | twait { 250 | h->_fd.write(crapbuf, size - pos > sizeof(crapbuf) ? sizeof(crapbuf) : size - pos, make_event(r)); 251 | } 252 | 253 | release: 254 | put(h); 255 | } 256 | 257 | } 258 | -------------------------------------------------------------------------------- /tamer/fdhelp.cc: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #ifdef __linux__ 11 | #include 12 | #endif 13 | #include 14 | #include 15 | #include "fdhmsg.cc" 16 | 17 | void terminate(int); 18 | int query_count = 0; 19 | 20 | int fdh_send(int fd, int fd_to_send, char * buf, size_t len) { 21 | struct iovec iov[1]; 22 | struct msghdr msgh; 23 | struct cmsghdr *cmsg; 24 | char anc[CMSG_SPACE(sizeof(int))]; 25 | 26 | iov[0].iov_base = buf; 27 | iov[0].iov_len = len; 28 | 29 | msgh.msg_iov = iov; 30 | msgh.msg_iovlen = 1; 31 | 32 | msgh.msg_name = NULL; 33 | msgh.msg_namelen = 0; 34 | 35 | if (fd_to_send < 0) { 36 | msgh.msg_control = NULL; 37 | msgh.msg_controllen = 0; 38 | } else { 39 | msgh.msg_control = anc; 40 | msgh.msg_controllen = sizeof(anc); 41 | 42 | cmsg = CMSG_FIRSTHDR(&msgh); 43 | cmsg->cmsg_level = SOL_SOCKET; 44 | cmsg->cmsg_type = SCM_RIGHTS; 45 | cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 46 | memcpy(CMSG_DATA(cmsg), &fd_to_send, sizeof(int)); 47 | 48 | msgh.msg_controllen = cmsg->cmsg_len; 49 | } 50 | 51 | msgh.msg_flags = 0; 52 | 53 | return sendmsg(fd, &msgh, 0); 54 | } 55 | 56 | int main (void) { 57 | char buf[8192]; 58 | int len; 59 | int fd; 60 | 61 | pid_t pid; 62 | int socks[2], chfd; 63 | 64 | fdh_msg * msg; 65 | 66 | char * fname; 67 | struct stat * stat; 68 | 69 | size_t size; 70 | ssize_t ssize; 71 | 72 | if (signal(SIGTERM, terminate) == SIG_ERR) { 73 | perror("unable to set signal"); 74 | exit(0); 75 | } 76 | 77 | for (;;) { 78 | if ((len = fdh_recv(0, &fd, buf, sizeof(buf))) < 0) { 79 | perror("recvmsg"); 80 | goto exit_; 81 | } else if (len == 0) 82 | goto exit_; 83 | 84 | query_count ++; 85 | msg = (fdh_msg *)buf; 86 | 87 | switch (msg->query.req) { 88 | case FDH_CLONE: 89 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, socks) < 0) { 90 | chfd = -1; 91 | msg->reply.err = errno; 92 | goto forkerr; 93 | } 94 | 95 | msg->reply.pid = pid = fork(); 96 | if (pid < 0) { 97 | chfd = -1; 98 | msg->reply.err = errno; 99 | goto forkerr; 100 | } else if (pid == 0) { 101 | // child 102 | close(0); 103 | close(socks[0]); 104 | if (dup2(socks[1], 0) < 0) { 105 | close(socks[1]); 106 | goto exit_; 107 | } 108 | close(socks[1]); 109 | break; 110 | } 111 | 112 | chfd = socks[0]; 113 | msg->reply.err = 0; 114 | forkerr: 115 | close(socks[1]); 116 | if (fdh_send(0, chfd, (char *)msg, FDH_MSG_SIZE) < 0) { 117 | perror("sendmsg"); 118 | close(socks[0]); 119 | goto exit_; 120 | } 121 | close(socks[0]); 122 | break; 123 | case FDH_OPEN: 124 | fname = (char *)&buf[FDH_MSG_SIZE]; 125 | msg->reply.err = ((fd = 126 | open(fname, msg->query.flags, msg->query.mode)) < 0) ? errno : 0; 127 | if (fdh_send(0, fd, (char *)msg, FDH_MSG_SIZE) < 0) { 128 | perror("sendmsg"); 129 | goto exit; 130 | } 131 | close(fd); 132 | break; 133 | case FDH_STAT: 134 | stat = (struct stat *)&buf[FDH_MSG_SIZE]; 135 | msg->reply.err = (fstat(fd, stat) < 0) ? errno : 0; 136 | if (fdh_send(0, -1, (char *)msg, FDH_MSG_SIZE + sizeof(struct stat)) < 0) { 137 | perror("sendmsg"); 138 | goto exit; 139 | } 140 | close(fd); 141 | break; 142 | case FDH_READ: 143 | #if __linux__ 144 | if (sendfile(0, fd, NULL, msg->query.size) < 0) { 145 | /* TODO handle error gracefully ?*/ 146 | perror("sendfile"); 147 | goto exit; 148 | } 149 | close(fd); 150 | break; 151 | #else 152 | perror("no sendfile"); 153 | goto exit; 154 | #endif 155 | case FDH_WRITE: 156 | size = msg->query.size; 157 | do { 158 | if ((ssize = read(0, buf, sizeof(buf))) < 0) { 159 | /* TODO handle error gracefully ? signal to parent?*/ 160 | perror("helper: read"); 161 | goto exit; 162 | } else if (ssize == 0) 163 | break; 164 | if (ssize) 165 | if (ssize != write(fd, buf, (size_t)ssize)) { 166 | /* TODO handle error gracefully ? signal to parent?*/ 167 | perror("helper: write"); 168 | goto exit; 169 | } 170 | size -= ssize; 171 | } while (size); 172 | close(fd); 173 | break; 174 | default: 175 | fprintf(stderr, "Unknown request\n"); 176 | goto exit; 177 | break; 178 | } 179 | } 180 | 181 | exit: 182 | close(fd); 183 | exit_: 184 | //TODO send signal to parent and restart loop instead of exiting (maybe) 185 | terminate(0); 186 | } 187 | 188 | void terminate(int) { 189 | //printf("exit %d query_count %d\n", getpid(), query_count); 190 | close(0); 191 | exit(0); 192 | } 193 | 194 | -------------------------------------------------------------------------------- /tamer/fdhmsg.cc: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #ifdef __linux__ 10 | #include 11 | #endif 12 | #include 13 | 14 | int fdh_recv(int fd, int * fd_to_recv, char * buf, size_t len) { 15 | int r; 16 | int fdt; 17 | struct iovec iov[1]; 18 | struct msghdr msgh; 19 | struct cmsghdr *cmsg; 20 | char anc[CMSG_SPACE(sizeof(int))]; 21 | 22 | iov[0].iov_base = buf; 23 | iov[0].iov_len = len; 24 | 25 | msgh.msg_iov = iov; 26 | msgh.msg_iovlen = 1; 27 | 28 | msgh.msg_name = NULL; 29 | msgh.msg_namelen = 0; 30 | 31 | msgh.msg_control = anc; 32 | msgh.msg_controllen = sizeof(anc); 33 | 34 | if ((r = recvmsg(fd, &msgh, 0)) < 0) 35 | return r; 36 | 37 | if (msgh.msg_controllen > 0) { 38 | cmsg = CMSG_FIRSTHDR(&msgh); 39 | if (cmsg->cmsg_len == sizeof(anc) && cmsg->cmsg_type == SCM_RIGHTS) { 40 | fdt = *(int *)CMSG_DATA(cmsg); 41 | if (fd_to_recv != NULL) 42 | *fd_to_recv = fdt; 43 | else 44 | close(fdt); 45 | } 46 | } else if (fd_to_recv != NULL) 47 | *fd_to_recv = -1; 48 | 49 | return r; 50 | } 51 | -------------------------------------------------------------------------------- /tamer/fdhmsg.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAMER_FDHELP_HH 2 | #define TAMER_FDHELP_HH 1 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define FDH_CLONE 100 10 | //#define FDH_KILL 101 11 | #define FDH_OPEN 102 12 | #define FDH_STAT 103 13 | #define FDH_READ 104 14 | #define FDH_WRITE 105 15 | 16 | //TODO add old unices support (if needed) i.e. msg_control -> msg_accrights 17 | 18 | /* clone 19 | * > msg: req 20 | * < msg: errno | pid; [anc: fd] 21 | * 22 | * kill 23 | * > msg: req 24 | * 25 | * open 26 | * > msg: req | int (flag) | mode | filename 27 | * < msg: errno; [anc: fd] 28 | * 29 | * stat 30 | * > msg: req, anc: fd 31 | * < msg: errno | [stat] 32 | * 33 | * read 34 | * > msg: req | size; anc: fd 35 | * < sendfile: pipe, fd, NULL, size 36 | * 37 | * write 38 | * > msg: req | size; anc: fd 39 | * > write: pipe 40 | * < read: pipe -> write: fd 41 | */ 42 | 43 | union fdh_msg { 44 | struct { 45 | uint8_t req; 46 | union { 47 | size_t size; 48 | int flags; 49 | }; 50 | mode_t mode; 51 | } query; 52 | struct { 53 | int err; 54 | pid_t pid; 55 | } reply; 56 | };//stat and fname placed at the end 57 | 58 | typedef union fdh_msg fdh_msg; 59 | 60 | #define FDH_MSG_SIZE sizeof(union fdh_msg) 61 | 62 | int fdh_recv(int fd, int * fd_to_recv, char * buf, size_t len); 63 | 64 | #endif /*TAMER_FDHELP_HH*/ 65 | -------------------------------------------------------------------------------- /tamer/http_parser.c: -------------------------------------------------------------------------------- 1 | /* Don't want untracked content in the http-parser directory */ 2 | #include "http-parser/http_parser.c" 3 | -------------------------------------------------------------------------------- /tamer/lock.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAMER_LOCK_HH 2 | #define TAMER_LOCK_HH 1 3 | /* Copyright (c) 2007-2015, Eddie Kohler 4 | * Copyright (c) 2007, Regents of the University of California 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a 7 | * copy of this software and associated documentation files (the "Software"), 8 | * to deal in the Software without restriction, subject to the conditions 9 | * listed in the Tamer LICENSE file. These conditions include: you must 10 | * preserve this copyright notice, and you cannot mention the copyright 11 | * holders in advertising related to the Software without their permission. 12 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 13 | * notice is a summary of the Tamer LICENSE file; the license in that file is 14 | * legally binding. 15 | */ 16 | #include 17 | namespace tamer { 18 | 19 | /** @file 20 | * @brief Classes for event-based synchronization. 21 | */ 22 | 23 | class mutex { 24 | public: 25 | inline mutex(); 26 | 27 | inline void acquire(event<> done); 28 | inline void release(); 29 | 30 | inline void acquire_shared(event<> done); 31 | inline void release_shared(); 32 | 33 | private: 34 | struct wait { 35 | wait **pprev; 36 | wait *next; 37 | event<> e; 38 | }; 39 | 40 | int locked_; 41 | wait *wait_; 42 | wait **wait_tailp_; 43 | 44 | void acquire(int shared, event<> done); 45 | class closure__acquire__iQ_; 46 | void acquire(closure__acquire__iQ_ &); 47 | 48 | void wake() { 49 | if (wait_) 50 | wait_->e.trigger(); 51 | } 52 | 53 | mutex(const mutex &); 54 | mutex &operator=(const mutex &); 55 | }; 56 | 57 | /** @brief Default constructor creates a mutex. */ 58 | inline mutex::mutex() 59 | : locked_(0), wait_(), wait_tailp_(&wait_) { 60 | } 61 | 62 | /** @brief Acquire the mutex for exclusive access. 63 | * @param done Event triggered when the mutex is acquired. 64 | * 65 | * The mutex must later be released with the release() method. 66 | */ 67 | inline void mutex::acquire(event<> done) { 68 | acquire(-1, done); 69 | } 70 | 71 | /** @brief Release a mutex acquired for exclusive access. 72 | * @pre The mutex must currently be acquired for exclusive access. 73 | * @sa acquire() 74 | */ 75 | inline void mutex::release() { 76 | assert(locked_ == -1); 77 | ++locked_; 78 | wake(); 79 | } 80 | 81 | /** @brief Acquire the mutex for shared access. 82 | * @param done Event triggered when the mutex is acquired. 83 | * 84 | * The mutex must later be released with the release_shared() method. 85 | */ 86 | inline void mutex::acquire_shared(event<> done) { 87 | acquire(1, done); 88 | } 89 | 90 | /** @brief Release a mutex acquired for shared access. 91 | * @pre The mutex must currently be acquired for shared access. 92 | * @sa acquire_shared() 93 | */ 94 | inline void mutex::release_shared() { 95 | assert(locked_ != -1 && locked_ != 0); 96 | --locked_; 97 | wake(); 98 | } 99 | 100 | } /* namespace tamer */ 101 | #endif /* TAMER_LOCK_HH */ 102 | -------------------------------------------------------------------------------- /tamer/lock.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++; related-file-name: "lock.hh" -*- 2 | /* Copyright (c) 2007-2015, Eddie Kohler 3 | * Copyright (c) 2007, Regents of the University of California 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a 6 | * copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, subject to the conditions 8 | * listed in the Tamer LICENSE file. These conditions include: you must 9 | * preserve this copyright notice, and you cannot mention the copyright 10 | * holders in advertising related to the Software without their permission. 11 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 12 | * notice is a summary of the Tamer LICENSE file; the license in that file is 13 | * legally binding. 14 | */ 15 | #include "config.h" 16 | #include 17 | #include 18 | namespace tamer { 19 | 20 | /** @class mutex tamer/lock.hh 21 | * @brief An event-based mutual-exclusion lock. 22 | * 23 | * A mutex object is an event-based mutual-exclusion and/or read/write lock. 24 | * Acquire the mutex with the acquire() method, which triggers its event<> 25 | * argument when the mutex is acquired. Later, release it with the release() 26 | * method. 27 | * 28 | * The mutex class also provides shared access, as for a read lock. Acquire 29 | * the mutex for shared access with the acquire_shared() method, and release 30 | * it thereafter with the release_shared() method. More than one callback 31 | * function can acquire_shared() a mutex at once, but all the shared 32 | * acquirers must release_shared() the mutex before a subsequent acquire() 33 | * will succeed. 34 | * 35 | * Acquire requests are served strictly in order of their arrival. For 36 | * example, the following code: 37 | * 38 | * @code 39 | * tamer::mutex m; 40 | * tamed void exclusive(int which) { 41 | * twait { m.acquire(make_event()); } 42 | * printf("%d: acquired\n", which); 43 | * twait { tamer::at_delay_sec(1, make_event()); } 44 | * m.release(); 45 | * printf("%d: released\n", which); 46 | * } 47 | * tamed void shared(int which) { 48 | * twait { m.acquire_shared(make_event()); } 49 | * printf("%d: acquired shared\n", which); 50 | * twait { tamer::at_delay_sec(1, make_event()); } 51 | * m.release_shared(); 52 | * printf("%d: released shared\n", which); 53 | * } 54 | * int main(int argc, char *argv[]) { 55 | * tamer::initialize(); 56 | * exclusive(1); 57 | * shared(2); 58 | * shared(3); 59 | * exclusive(4); 60 | * shared(5); 61 | * tamer::loop(); 62 | * } 63 | * @endcode 64 | * 65 | * will generate this output: 66 | * 67 | *
 68 |  *     1: acquired
 69 |  *     1: released
 70 |  *     2: acquired shared
 71 |  *     3: acquired shared
 72 |  *     2: released shared
 73 |  *     3: released shared
 74 |  *     4: acquired
 75 |  *     4: released
 76 |  *     5: acquired shared
 77 |  *     5: released shared
 78 |  *  
79 | */ 80 | 81 | tamed void mutex::acquire(int shared, event<> done) { 82 | tvars { 83 | rendezvous<> r; 84 | wait w; 85 | } 86 | 87 | if (!done) { 88 | return; 89 | } 90 | if (!wait_ && (shared > 0 ? locked_ != -1 : locked_ == 0)) { 91 | locked_ += shared; 92 | done.trigger(); 93 | return; 94 | } 95 | 96 | done.at_trigger(make_event(r)); 97 | w.e = make_event(r); 98 | w.pprev = wait_tailp_; 99 | *w.pprev = &w; 100 | wait_tailp_ = &w.next; 101 | w.next = 0; 102 | 103 | while (true) { 104 | twait(r); 105 | if (!done) { 106 | // canceling an exclusive lock may let a shared lock through, 107 | // so always count canceled locks as shared 108 | shared = 1; 109 | break; 110 | } else if (shared > 0 ? locked_ != -1 : locked_ == 0) { 111 | // obtained lock 112 | locked_ += shared; 113 | break; 114 | } else { 115 | // must try again 116 | w.e = make_event(r); // w is still on front 117 | } 118 | } 119 | 120 | done.trigger(); // lock was obtained (or done is empty) 121 | r.clear(); // not interested in r events, so clean up 122 | *w.pprev = w.next; // remove wait object from list 123 | if (w.next) { 124 | w.next->pprev = w.pprev; 125 | } else { 126 | wait_tailp_ = w.pprev; 127 | } 128 | if (shared > 0) { // next waiter might also get a shared lock 129 | wake(); 130 | } 131 | } 132 | 133 | } // namespace tamer 134 | -------------------------------------------------------------------------------- /tamer/tamer.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAMER_TAMER_HH 2 | #define TAMER_TAMER_HH 1 3 | /* Copyright (c) 2007-2015, Eddie Kohler 4 | * Copyright (c) 2007, Regents of the University of California 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a 7 | * copy of this software and associated documentation files (the "Software"), 8 | * to deal in the Software without restriction, subject to the conditions 9 | * listed in the Tamer LICENSE file. These conditions include: you must 10 | * preserve this copyright notice, and you cannot mention the copyright 11 | * holders in advertising related to the Software without their permission. 12 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 13 | * notice is a summary of the Tamer LICENSE file; the license in that file is 14 | * legally binding. 15 | */ 16 | 17 | /** @mainpage Tamer 18 | * @section Introduction 19 | * 20 | * Tamer is a C++ language extension and library that simplifies event-driven 21 | * programming. Functions in Tamer can block to wait for an event, then 22 | * resume computation later. While one function is blocked, other functions 23 | * can continue their computation. This is as easy as threaded programming, 24 | * but avoids most synchronization and locking issues and generally requires 25 | * less memory. 26 | * 27 | * Most documented Tamer functions and classes can be found under the 28 | * "Namespaces" and "Classes" tabs. 29 | * 30 | * Main Tamer page 31 | */ 32 | 33 | /** @file 34 | * @brief The main Tamer header file. 35 | */ 36 | 37 | /** @namespace tamer 38 | * @brief Namespace containing public Tamer classes and functions for the 39 | * Tamer core. 40 | */ 41 | 42 | /** @brief Major version number for this Tamer release. */ 43 | #define TAMER_MAJOR_VERSION 1 44 | /** @brief Minor version number for this Tamer release. */ 45 | #define TAMER_MINOR_VERSION 9 46 | /** @brief Release level for this Tamer release. */ 47 | #define TAMER_RELEASE_LEVEL 0 48 | 49 | #include 50 | #include 51 | #include 52 | #include 53 | 54 | #endif /* TAMER_TAMER_HH */ 55 | -------------------------------------------------------------------------------- /tamer/tamer.pc.in: -------------------------------------------------------------------------------- 1 | prefix=@prefix@ 2 | exec_prefix=@exec_prefix@ 3 | libdir=@libdir@ 4 | includedir=@includedir@ 5 | 6 | Name: Tamer 7 | Description: Library and language processor for event-driven programming 8 | Version: @VERSION@ 9 | URL: http://www.read.cs.ucla.edu/tamer/ 10 | Libs: @SANITIZER_FLAGS@ -L${libdir} -ltamer @DRIVER_LIBS@ 11 | Cflags: @SANITIZER_FLAGS@ -I${includedir} 12 | -------------------------------------------------------------------------------- /tamer/websocket.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAMER_WEBSOCKET_HH 2 | #define TAMER_WEBSOCKET_HH 1 3 | #include "http.hh" 4 | namespace tamer { 5 | 6 | class websocket_handshake { 7 | public: 8 | static bool request(http_message& req, std::string& key); 9 | static bool is_request(const http_message& req); 10 | static bool response(http_message& resp, const http_message& req); 11 | static bool is_response(const http_message& resp, const std::string& key); 12 | }; 13 | 14 | enum websocket_opcode { 15 | WEBSOCKET_CONTINUATION = 0, 16 | WEBSOCKET_TEXT = 1, 17 | WEBSOCKET_BINARY = 2, 18 | WEBSOCKET_CLOSE = 8, 19 | WEBSOCKET_PING = 9, 20 | WEBSOCKET_PONG = 10 21 | }; 22 | 23 | class websocket_message { 24 | public: 25 | inline websocket_message(); 26 | 27 | inline bool ok() const; 28 | inline bool operator!() const; 29 | inline enum http_errno error() const; 30 | 31 | inline enum websocket_opcode opcode() const; 32 | inline bool text() const; 33 | inline bool binary() const; 34 | inline bool incomplete() const; 35 | inline const std::string& body() const; 36 | inline std::string& body(); 37 | 38 | inline websocket_message& clear(); 39 | 40 | inline websocket_message& error(enum http_errno e); 41 | inline websocket_message& incomplete(bool c); 42 | inline websocket_message& opcode(enum websocket_opcode o); 43 | inline websocket_message& body(std::string body); 44 | inline websocket_message& text(std::string body); 45 | inline websocket_message& binary(std::string body); 46 | 47 | private: 48 | unsigned error_ : 8; 49 | unsigned incomplete_ : 4; 50 | unsigned opcode_ : 4; 51 | std::string body_; 52 | }; 53 | 54 | class websocket_parser : public tamed_class { 55 | public: 56 | inline websocket_parser(enum http_parser_type type); 57 | 58 | inline bool ok() const; 59 | inline bool operator!() const; 60 | inline bool closed() const; 61 | 62 | void receive_any(fd f, websocket_message& ctrl, websocket_message& data, event done); 63 | void receive(fd f, event done); 64 | void send(fd f, websocket_message m, event<> done); 65 | inline void send_text(fd f, std::string text, event<> done); 66 | inline void send_binary(fd f, std::string text, event<> done); 67 | void close(fd f, uint16_t code, std::string reason, event<> done); 68 | inline void close(fd f, uint16_t code, event<> done); 69 | 70 | private: 71 | enum http_parser_type type_; 72 | uint8_t closed_; 73 | uint16_t close_code_; 74 | std::string close_reason_; 75 | 76 | class closure__receive_any__2fdR17websocket_messageR17websocket_messageQi_; 77 | void receive_any(closure__receive_any__2fdR17websocket_messageR17websocket_messageQi_&); 78 | class closure__receive__2fdQ17websocket_message_; 79 | void receive(closure__receive__2fdQ17websocket_message_&); 80 | class closure__send__2fd17websocket_messageQ_; 81 | void send(closure__send__2fd17websocket_messageQ_&); 82 | }; 83 | 84 | inline websocket_message::websocket_message() 85 | : error_(0), incomplete_(0), opcode_(0) { 86 | } 87 | 88 | inline bool websocket_message::ok() const { 89 | return error_ == 0; 90 | } 91 | 92 | inline bool websocket_message::operator!() const { 93 | return !ok(); 94 | } 95 | 96 | inline enum http_errno websocket_message::error() const { 97 | return http_errno(error_); 98 | } 99 | 100 | inline enum websocket_opcode websocket_message::opcode() const { 101 | return websocket_opcode(opcode_); 102 | } 103 | 104 | inline bool websocket_message::text() const { 105 | return websocket_opcode(opcode_) == WEBSOCKET_TEXT; 106 | } 107 | 108 | inline bool websocket_message::binary() const { 109 | return websocket_opcode(opcode_) == WEBSOCKET_BINARY; 110 | } 111 | 112 | inline bool websocket_message::incomplete() const { 113 | return incomplete_; 114 | } 115 | 116 | inline const std::string& websocket_message::body() const { 117 | return body_; 118 | } 119 | 120 | inline std::string& websocket_message::body() { 121 | return body_; 122 | } 123 | 124 | inline websocket_message& websocket_message::clear() { 125 | error_ = 0; 126 | incomplete_ = 0; 127 | opcode_ = 0; 128 | body_.clear(); 129 | return *this; 130 | } 131 | 132 | inline websocket_message& websocket_message::error(enum http_errno e) { 133 | error_ = e; 134 | return *this; 135 | } 136 | 137 | inline websocket_message& websocket_message::incomplete(bool c) { 138 | incomplete_ = c; 139 | return *this; 140 | } 141 | 142 | inline websocket_message& websocket_message::opcode(enum websocket_opcode o) { 143 | opcode_ = o; 144 | return *this; 145 | } 146 | 147 | inline websocket_message& websocket_message::body(std::string s) { 148 | body_ = TAMER_MOVE(s); 149 | return *this; 150 | } 151 | 152 | inline websocket_message& websocket_message::text(std::string s) { 153 | opcode_ = WEBSOCKET_TEXT; 154 | body_ = TAMER_MOVE(s); 155 | return *this; 156 | } 157 | 158 | inline websocket_message& websocket_message::binary(std::string s) { 159 | opcode_ = WEBSOCKET_BINARY; 160 | body_ = TAMER_MOVE(s); 161 | return *this; 162 | } 163 | 164 | inline websocket_parser::websocket_parser(enum http_parser_type type) 165 | : type_(type), closed_(0), close_code_(0) { 166 | } 167 | 168 | inline bool websocket_parser::ok() const { 169 | return !closed_; 170 | } 171 | 172 | inline bool websocket_parser::operator!() const { 173 | return closed_; 174 | } 175 | 176 | inline bool websocket_parser::closed() const { 177 | return closed_; 178 | } 179 | 180 | inline void websocket_parser::send_text(fd f, std::string s, event<> done) { 181 | send(f, websocket_message().text(s), done); 182 | } 183 | 184 | inline void websocket_parser::send_binary(fd f, std::string s, event<> done) { 185 | send(f, websocket_message().binary(s), done); 186 | } 187 | 188 | inline void websocket_parser::close(fd f, uint16_t close_code, event<> done) { 189 | close(f, close_code, std::string(), done); 190 | } 191 | 192 | } 193 | #endif 194 | -------------------------------------------------------------------------------- /tamer/xadapter.cc: -------------------------------------------------------------------------------- 1 | /* Copyright (c) 2007-2015, Eddie Kohler 2 | * Copyright (c) 2007, Regents of the University of California 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #include 16 | #include 17 | namespace tamer { 18 | namespace tamerpriv { 19 | 20 | char placeholder_buffer[64]; 21 | 22 | void with_helper_rendezvous::hook(functional_rendezvous *fr, 23 | simple_event *, bool) TAMER_NOEXCEPT { 24 | with_helper_rendezvous *self = static_cast(fr); 25 | if (*self->e_) { 26 | *self->s0_ = self->v0_; 27 | tamerpriv::simple_event::use(self->e_); 28 | self->e_->simple_trigger(false); 29 | } else 30 | *self->s0_ = int(); 31 | delete self; 32 | } 33 | 34 | }} 35 | -------------------------------------------------------------------------------- /tamer/xdriver.hh: -------------------------------------------------------------------------------- 1 | #ifndef TAMER_XDRIVER_HH 2 | #define TAMER_XDRIVER_HH 1 3 | /* Copyright (c) 2007-2015, Eddie Kohler 4 | * Copyright (c) 2007, Regents of the University of California 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a 7 | * copy of this software and associated documentation files (the "Software"), 8 | * to deal in the Software without restriction, subject to the conditions 9 | * listed in the Tamer LICENSE file. These conditions include: you must 10 | * preserve this copyright notice, and you cannot mention the copyright 11 | * holders in advertising related to the Software without their permission. 12 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 13 | * notice is a summary of the Tamer LICENSE file; the license in that file is 14 | * legally binding. 15 | */ 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | namespace tamer { 23 | namespace tamerpriv { 24 | extern struct timeval recent; 25 | extern bool need_recent; 26 | } // namespace tamerpriv 27 | 28 | enum loop_flags { 29 | loop_default = 0, 30 | loop_forever = 0, 31 | loop_once = 1 32 | }; 33 | 34 | enum signal_flags { 35 | signal_default = 0, 36 | signal_background = 1 37 | }; 38 | 39 | enum fd_actions { 40 | fd_read = 0, 41 | fd_write = 1, // order matters 42 | fd_hangup = 2, 43 | nfdactions = 3 44 | }; 45 | 46 | class driver : public tamerpriv::simple_driver { 47 | public: 48 | driver(); 49 | virtual ~driver(); 50 | 51 | enum { capacity = (unsigned) 256 }; 52 | static inline driver* by_index(unsigned index); 53 | inline unsigned index() const; 54 | 55 | // basic functions 56 | virtual void at_fd(int fd, int action, event e) = 0; 57 | virtual void at_time(const timeval& expiry, event<> e, bool bg) = 0; 58 | virtual void at_asap(event<> e) = 0; 59 | virtual void at_preblock(event<> e) = 0; 60 | virtual void kill_fd(int fd) = 0; 61 | 62 | inline void at_fd(int fd, int action, event<> e); 63 | inline void at_time(const timeval& expiry, event<> e); 64 | inline void at_time(double expiry, event<> e, bool bg = false); 65 | inline void at_delay(timeval delay, event<> e, bool bg = false); 66 | void at_delay(double delay, event<> e, bool bg = false); 67 | inline void at_delay_sec(int delay, event<> e, bool bg = false); 68 | inline void at_delay_msec(int delay, event<> e, bool bg = false); 69 | inline void at_delay_usec(int delay, event<> e, bool bg = false); 70 | 71 | static void at_signal(int signo, event<> e, 72 | signal_flags flags = signal_default); 73 | 74 | typedef void (*error_handler_type)(int fd, int err, std::string msg); 75 | virtual void set_error_handler(error_handler_type errh); 76 | 77 | virtual void loop(loop_flags flag) = 0; 78 | virtual void break_loop() = 0; 79 | virtual timeval next_wake() const; 80 | 81 | virtual void clear(); 82 | 83 | void blocked_locations(std::vector& x); 84 | 85 | static driver* make_tamer(int flags); 86 | static driver* make_libevent(); 87 | static driver* make_libev(); 88 | 89 | static driver* main; 90 | 91 | static volatile sig_atomic_t sig_any_active; 92 | static int sig_pipe[2]; 93 | static unsigned sig_nforeground; 94 | static unsigned sig_ntotal; 95 | void dispatch_signals(); 96 | 97 | private: 98 | unsigned index_; 99 | std::tuple int_placeholder_; 100 | 101 | static driver* indexed[capacity]; 102 | static int next_index; 103 | }; 104 | 105 | timeval now(); 106 | inline const timeval& recent(); 107 | 108 | inline driver* driver::by_index(unsigned index) { 109 | return index < capacity ? indexed[index] : 0; 110 | } 111 | 112 | inline unsigned driver::index() const { 113 | return index_; 114 | } 115 | 116 | inline void driver::at_fd(int fd, int action, event<> e) { 117 | at_fd(fd, action, event(e, int_placeholder_)); 118 | } 119 | 120 | inline void driver::at_time(const timeval& expiry, event<> e) { 121 | at_time(expiry, e, false); 122 | } 123 | 124 | inline void driver::at_time(double expiry, event<> e, bool bg) { 125 | timeval tv; 126 | tv.tv_sec = (long) expiry; 127 | tv.tv_usec = (long) ((expiry - tv.tv_sec) * 1000000); 128 | at_time(tv, e, bg); 129 | } 130 | 131 | inline void driver::at_delay(timeval delay, event<> e, bool bg) { 132 | timeradd(&delay, &recent(), &delay); 133 | at_time(delay, e, bg); 134 | } 135 | 136 | inline void driver::at_delay_sec(int delay, event<> e, bool bg) { 137 | if (delay <= 0) { 138 | at_asap(e); 139 | } else { 140 | timeval tv = recent(); 141 | tv.tv_sec += delay; 142 | at_time(tv, e, bg); 143 | } 144 | } 145 | 146 | inline void driver::at_delay_msec(int delay, event<> e, bool bg) { 147 | if (delay <= 0) { 148 | at_asap(e); 149 | } else { 150 | timeval tv; 151 | tv.tv_sec = delay / 1000; 152 | tv.tv_usec = (delay % 1000) * 1000; 153 | at_delay(tv, e, bg); 154 | } 155 | } 156 | 157 | inline void driver::at_delay_usec(int delay, event<> e, bool bg) { 158 | if (delay <= 0) { 159 | at_asap(e); 160 | } else { 161 | timeval tv; 162 | tv.tv_sec = delay / 1000000; 163 | tv.tv_usec = delay % 1000000; 164 | at_delay(tv, e, bg); 165 | } 166 | } 167 | 168 | namespace tamerpriv { 169 | inline void blocking_rendezvous::block(closure& c, unsigned position) { 170 | block(tamer::driver::main, c, position); 171 | } 172 | } // namespace tamerpriv 173 | } // namespace tamer 174 | #endif /* TAMER_XDRIVER_HH */ 175 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_PROGRAMS = t01 t02 t03 t04 t05 t06 t07 t08 t09 t10 \ 2 | t11 t12 t13 t14 t15 t16 t17 t18 t19 t20 \ 3 | t21 t22 t23 t24 t25 t26 t27 t28 t29 t30 4 | 5 | t01_SOURCES = t01.tcc 6 | t02_SOURCES = t02.tt 7 | t03_SOURCES = t03.tcc 8 | t04_SOURCES = t04.tt 9 | t05_SOURCES = t05.tt 10 | t06_SOURCES = t06.tcc 11 | t07_SOURCES = t07.tcc 12 | t08_SOURCES = t08.tcc 13 | t09_SOURCES = t09.tcc 14 | t10_SOURCES = t10.tcc 15 | t11_SOURCES = t11.tcc 16 | t12_SOURCES = t12.tcc 17 | t13_SOURCES = t13.tcc 18 | t14_SOURCES = t14.tcc 19 | t15_SOURCES = t15.tcc 20 | t16_SOURCES = t16.tcc 21 | t17_SOURCES = t17.tcc 22 | t18_SOURCES = t18.tcc 23 | t19_SOURCES = t19.tcc 24 | t20_SOURCES = t20.tcc 25 | t21_SOURCES = t21.tcc 26 | t22_SOURCES = t22.tcc 27 | t23_SOURCES = t23.tcc 28 | t24_SOURCES = t24.tcc 29 | t25_SOURCES = t25.tcc 30 | t26_SOURCES = t26.tcc 31 | t27_SOURCES = t27.tcc 32 | t28_SOURCES = t28.tcc 33 | t29_SOURCES = t29.tcc 34 | t30_SOURCES = t30.tcc 35 | 36 | DRIVER_LIBS = @DRIVER_LIBS@ 37 | MALLOC_LIBS = @MALLOC_LIBS@ 38 | LDADD = ../tamer/libtamer.la $(DRIVER_LIBS) $(MALLOC_LIBS) 39 | AM_LDFLAGS = -static 40 | 41 | AM_CPPFLAGS = -I$(top_srcdir) -I$(top_builddir) 42 | DEFS = -DTAMER_DEBUG 43 | 44 | if TAMER_SANITIZERS 45 | AM_CXXFLAGS = @SANITIZER_FLAGS@ 46 | AM_LDFLAGS += @SANITIZER_FLAGS@ 47 | endif 48 | 49 | TAMER = ../compiler/tamer 50 | .tt.cc: 51 | $(TAMER) -g -o $@ -c $< || (rm $@ && false) 52 | .tcc.cc: 53 | $(TAMER) -g -o $@ -c $< || (rm $@ && false) 54 | 55 | t01.cc: $(srcdir)/t01.tcc $(TAMER) 56 | t02.cc: $(srcdir)/t02.tt $(TAMER) 57 | t03.cc: $(srcdir)/t03.tcc $(TAMER) 58 | t04.cc: $(srcdir)/t04.tt $(TAMER) 59 | t05.cc: $(srcdir)/t05.tt $(TAMER) 60 | t06.cc: $(srcdir)/t06.tcc $(TAMER) 61 | t07.cc: $(srcdir)/t07.tcc $(TAMER) 62 | t08.cc: $(srcdir)/t08.tcc $(TAMER) 63 | t09.cc: $(srcdir)/t09.tcc $(TAMER) 64 | t10.cc: $(srcdir)/t10.tcc $(TAMER) 65 | t11.cc: $(srcdir)/t11.tcc $(TAMER) 66 | t12.cc: $(srcdir)/t12.tcc $(TAMER) 67 | t13.cc: $(srcdir)/t13.tcc $(TAMER) 68 | t14.cc: $(srcdir)/t14.tcc $(TAMER) 69 | t15.cc: $(srcdir)/t15.tcc $(TAMER) 70 | t16.cc: $(srcdir)/t16.tcc $(TAMER) 71 | t17.cc: $(srcdir)/t17.tcc $(TAMER) 72 | t18.cc: $(srcdir)/t18.tcc $(TAMER) 73 | t19.cc: $(srcdir)/t19.tcc $(TAMER) 74 | t20.cc: $(srcdir)/t20.tcc $(TAMER) 75 | t21.cc: $(srcdir)/t21.tcc $(TAMER) 76 | t22.cc: $(srcdir)/t22.tcc $(TAMER) 77 | t23.cc: $(srcdir)/t23.tcc $(TAMER) 78 | t24.cc: $(srcdir)/t24.tcc $(TAMER) 79 | t25.cc: $(srcdir)/t25.tcc $(TAMER) 80 | t26.cc: $(srcdir)/t26.tcc $(TAMER) 81 | t27.cc: $(srcdir)/t27.tcc $(TAMER) 82 | t28.cc: $(srcdir)/t28.tcc $(TAMER) 83 | t29.cc: $(srcdir)/t29.tcc $(TAMER) 84 | t30.cc: $(srcdir)/t30.tcc $(TAMER) 85 | 86 | TAMED_CXXFILES = t01.cc t02.cc t03.cc t04.cc t05.cc t06.cc t07.cc t08.cc \ 87 | t09.cc t10.cc t11.cc t12.cc t13.cc t14.cc t15.cc t16.cc t17.cc \ 88 | t18.cc t19.cc t20.cc t21.cc t22.cc t23.cc t24.cc t25.cc t26.cc \ 89 | t27.cc t28.cc t29.cc t30.cc 90 | CLEANFILES = $(TAMED_CXXFILES) 91 | .PRECIOUS: $(TAMED_CXXFILES) 92 | -------------------------------------------------------------------------------- /test/t01.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Bag o' tests, including of some adapters. 3 | 4 | %script 5 | echo Wacky | $VALGRIND $rundir/test/t01 6 | 7 | %stderr 8 | :: waitr 0 9 | @0: triggered 1 10 | @0: triggered 100 11 | @0: triggered 101 12 | @0: triggered 102 13 | @0: triggered 1 1 14 | @0: triggered 2 2 15 | @0: triggered 3 3 16 | @0: done cancellina2 17 | @0: before bindery 1 18 | @0: before mappery 1 19 | :: stdin result 0 20 | @100: {{[\d.]+}} 21 | @250: {{[\d.]+}} 22 | @400: {{[\d.]+}} 23 | @500: distributed 1 {{[\d\s.]+}} 24 | @500: distributed 2 {{[\d\s.]+}} 25 | @500: distributed 3 {{[\d\s.]+}} 26 | @505: distributed 0 {{[\d\s.]+}} 27 | tamer: dropping last reference to active event 28 | {{tamer: .*: event was created here|}} 29 | @505: distributed 0 {{[\d\s.]+}} 30 | @600: after bindery 2 31 | @600: got bindery 32 | @600: after bindery 2 2 33 | @600: got bindery 34 | @600: after bindery 3 4 35 | @700: after mappery 3 36 | @700: before mappery 3 37 | @700: after mappery 3 38 | @700+: after mappery 11 39 | @1000: {{[\d.]+}} 40 | :: waitr 10 41 | @1005: distributed 1 {{[\d\s.]+}} 42 | @1005: distributed 2 {{[\d\s.]+}} 43 | @1005: distributed 3 {{[\d\s.]+}} 44 | tamer: dropping last reference to active event 45 | {{tamer: .*t01\.tcc:209: event was created here|}} 46 | DONE 47 | 48 | %ignore 49 | #{{.*}} 50 | {{^==\d+==.*}} 51 | .{{.*}} 52 | -------------------------------------------------------------------------------- /test/t02.tt: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2012, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | int n; 23 | 24 | tamed void asap(tamer::event<> e) { 25 | tvars { int i; } 26 | for (i = 0; i < 50000000; ++i) { 27 | twait { tamer::at_asap(make_event()); } 28 | } 29 | e.trigger(); 30 | } 31 | 32 | tamed void delay_bounds() { 33 | twait volatile { 34 | tamer::at_delay_sec(1, make_event()); 35 | tamer::at_delay_sec(100, make_event()); 36 | } 37 | } 38 | 39 | tamed void asapt(tamer::event<> e) { 40 | tvars { 41 | int i; 42 | } 43 | for (i = 0; i < 1000000; ++i) { 44 | twait { 45 | for (int j = 0; j < 4; ++j) { 46 | tamer::at_asap(tamer::with_timeout_sec(10, make_event())); 47 | } 48 | } 49 | } 50 | e.trigger(); 51 | } 52 | 53 | int main(int argc, char **argv) { 54 | tamer::initialize(); 55 | tamer::rendezvous<> r; 56 | tamer::event<> e = make_event(r); 57 | if (argc == 2 && strcmp(argv[1], "-t") == 0) { 58 | delay_bounds(); 59 | asapt(e); 60 | } else if (argc == 1) { 61 | asap(e); 62 | } else { 63 | fprintf(stderr, "Usage: ./t02 [-t]\n"); 64 | } 65 | tamer::loop(); 66 | tamer::cleanup(); 67 | } 68 | -------------------------------------------------------------------------------- /test/t03.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2007, Eddie Kohler 3 | * Copyright (c) 2007, Regents of the University of California 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a 6 | * copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, subject to the conditions 8 | * listed in the Tamer LICENSE file. These conditions include: you must 9 | * preserve this copyright notice, and you cannot mention the copyright 10 | * holders in advertising related to the Software without their permission. 11 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 12 | * notice is a summary of the Tamer LICENSE file; the license in that file is 13 | * legally binding. 14 | */ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | tamed void read_sucka(tamer::fd &f) { 24 | tvars { 25 | int ret(-1); 26 | char buf[40]; 27 | size_t amt(0); 28 | } 29 | twait { 30 | f.read(buf, 40, amt, tamer::add_timeout(0.5, make_event(ret), -ETIMEDOUT)); 31 | } 32 | if (ret < 0) { 33 | printf("got error %d (%s): %ld: %.*s\n", ret, strerror(-ret), (long) amt, (int) amt, buf); 34 | } else { 35 | printf("got %d: %ld: %.*s\n", ret, (long) amt, (int) amt, buf); 36 | } 37 | } 38 | 39 | tamed void time_sucka() { 40 | twait { tamer::at_delay_msec(250, make_event()); } 41 | } 42 | 43 | tamed void close_sucka(tamer::fd &f) { 44 | twait { tamer::at_delay_msec(125, make_event()); } 45 | f.close(); 46 | } 47 | 48 | 49 | int main(int, char **) { 50 | tamer::initialize(); 51 | tamer::fd::make_nonblocking(0); 52 | tamer::fd mystdin(0); 53 | read_sucka(mystdin); 54 | time_sucka(); 55 | close_sucka(mystdin); 56 | tamer::loop(); 57 | tamer::cleanup(); 58 | } 59 | -------------------------------------------------------------------------------- /test/t03.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Reading and cancellation. 3 | 4 | %script 5 | fsleep () { 6 | perl -e "select(undef,undef,undef,$1)" 7 | } 8 | 9 | $VALGRIND $rundir/test/t03 10 | echo Foo | $VALGRIND $rundir/test/t03 11 | (fsleep 0.25; echo Bar) | $VALGRIND $rundir/test/t03 12 | (echo Baz; fsleep 0.25; echo Quux) | $VALGRIND $rundir/test/t03 13 | echo 0123456789a123456789b123456789c123456789d123456789e123456789 | $VALGRIND $rundir/test/t03 14 | 15 | %stdout 16 | got 0: 0: 17 | got 0: 4: Foo 18 | 19 | got error -{{\d+}} (Operation canceled): 0: 20 | got error -{{\d+}} (Operation canceled): 4: Baz 21 | 22 | got 0: 40: 0123456789a123456789b123456789c123456789 23 | -------------------------------------------------------------------------------- /test/t04.tt: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | #include 3 | #include 4 | #include 5 | #define NUM_ITERS 50000000 6 | 7 | tamed void crunch2tamer(uint32_t x, uint32_t *r) { 8 | *r = x * 2 - 1; 9 | } 10 | 11 | tamed void crunch1tamer(uint32_t x, uint32_t *r) { 12 | crunch2tamer(x, r); 13 | *r *= -1; 14 | } 15 | 16 | void crunch2inline(uint32_t x, uint32_t *r) { 17 | *r = x * 2 - 1; 18 | } 19 | 20 | void crunch1inline(uint32_t x, uint32_t *r) { 21 | crunch2inline(x, r); 22 | *r *= -1; 23 | } 24 | 25 | void crunch2outline(uint32_t, uint32_t *) __attribute__((noinline)); 26 | void crunch2outline(uint32_t x, uint32_t *r) { 27 | *r = x * 2 - 1; 28 | } 29 | 30 | void crunch1outline(uint32_t, uint32_t *) __attribute__((noinline)); 31 | void crunch1outline(uint32_t x, uint32_t *r) { 32 | crunch2outline(x, r); 33 | *r *= -1; 34 | } 35 | 36 | int main(int argc, char **argv) { 37 | (void) argc, (void) argv; 38 | int i; 39 | 40 | uint32_t r = 1; 41 | 42 | if (argc == 1 || (argc > 1 && strcmp(argv[1], "tamer") == 0)) { 43 | for (i = 0; i < NUM_ITERS; i++) 44 | crunch1tamer(r, &r); 45 | } else if (argc > 1 && strcmp(argv[1], "inline") == 0) { 46 | for (i = 0; i < NUM_ITERS; i++) 47 | crunch1inline(r, &r); 48 | } else if (argc > 1 && strcmp(argv[1], "outline") == 0) { 49 | for (i = 0; i < NUM_ITERS; i++) 50 | crunch1outline(r, &r); 51 | } else 52 | std::cerr << "expected tamer, inline, or outline\n"; 53 | 54 | std::cout << r << "\n"; 55 | return 0; 56 | } 57 | -------------------------------------------------------------------------------- /test/t05.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Test string rendezvous values. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t05 6 | 7 | %stdout 8 | 3967 9 | 2259 10 | 2899 11 | 1831 12 | 1002 13 | 3624 14 | 2055 15 | 3099 16 | 3837 17 | 1118 18 | -------------------------------------------------------------------------------- /test/t05.tt: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2012, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | int n; 24 | 25 | uint32_t xseed = 23941792; 26 | uint32_t xrandom() { 27 | return (xseed = xseed * 1664525 + 1013904223); 28 | } 29 | 30 | tamed void test() { 31 | tvars { 32 | int j = 0; 33 | tamer::rendezvous r; 34 | std::string s; 35 | } 36 | for (int i = 0; i < 5000; ++i) { 37 | tamer::at_delay_usec(xrandom() % 100000, 38 | tamer::make_event(r, std::to_string(i))); 39 | } 40 | while (j < 10) { 41 | twait(r, s); 42 | fprintf(stdout, "%s\n", s.c_str()); 43 | ++j; 44 | } 45 | r.clear(); 46 | } 47 | 48 | int main(int, char **) { 49 | tamer::initialize(); 50 | test(); 51 | tamer::loop(); 52 | tamer::cleanup(); 53 | } 54 | -------------------------------------------------------------------------------- /test/t06.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2012, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | tamed void run_signals() { 22 | tvars { 23 | tamer::rendezvous r; 24 | int n = 0, what; 25 | } 26 | tamer::at_signal(SIGINT, make_event(r, 1)); 27 | tamer::at_signal(SIGUSR1, make_event(r, 2)); 28 | tamer::at_delay(100000, make_event(r, 3)); 29 | while (true) { 30 | twait(r, what); 31 | if (what == 1) { 32 | ++n; 33 | tamer::at_signal(SIGINT, make_event(r, 1)); 34 | } else { 35 | break; 36 | } 37 | } 38 | fprintf(stdout, "received %d SIGINT\n", n); 39 | fflush(stdout); 40 | r.clear(); 41 | } 42 | 43 | int main(int, char **) { 44 | tamer::initialize(); 45 | run_signals(); 46 | if (fork() == 0) { 47 | pid_t x = getppid(); 48 | for (int i = 0; i < 10000; ++i) { 49 | kill(x, SIGINT); 50 | usleep(1); 51 | } 52 | kill(x, SIGUSR1); 53 | exit(0); 54 | } 55 | tamer::loop(); 56 | tamer::cleanup(); 57 | } 58 | -------------------------------------------------------------------------------- /test/t06.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Test signal handling, in particular signal blocking. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t06 6 | 7 | %stdout 8 | received {{10000|9...}} SIGINT 9 | -------------------------------------------------------------------------------- /test/t07.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2013, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | template 23 | struct foo { 24 | tamed void doit(tamer::event<> e); 25 | }; 26 | 27 | tamed template 28 | void foo::doit(tamer::event<> e) { 29 | tamer::at_asap(e); 30 | } 31 | 32 | tamed void function() { 33 | tvars { foo f; } 34 | twait { f.doit(make_event()); } 35 | std::cout << "It happened\n"; 36 | } 37 | 38 | int main(int, char **) { 39 | tamer::initialize(); 40 | function(); 41 | tamer::loop(); 42 | tamer::cleanup(); 43 | } 44 | -------------------------------------------------------------------------------- /test/t07.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Test templated tamed functions. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t07 6 | 7 | %stdout 8 | It happened 9 | -------------------------------------------------------------------------------- /test/t08.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2013, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #undef TAMER_DEBUG 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | #if TAMER_HAVE_PREEVENT 25 | template 26 | void immediate_preevent(int i, tamer::preevent e) { 27 | if (i % 1024 == 0) 28 | tamer::at_asap(std::move(e)); 29 | else 30 | e(); 31 | } 32 | 33 | tamed void function_preevent() { 34 | twait { 35 | for (int i = 0; i < 10000000; ++i) 36 | immediate_preevent(i, make_preevent()); 37 | } 38 | std::cout << "It happened\n"; 39 | } 40 | #endif 41 | 42 | void immediate_event(int i, tamer::event<> e) { 43 | if (i % 1024 == 0) 44 | tamer::at_asap(e); 45 | else 46 | e(); 47 | } 48 | 49 | tamed void function_event() { 50 | twait { 51 | for (int i = 0; i < 10000000; ++i) 52 | immediate_event(i, make_event()); 53 | } 54 | std::cout << "It happened\n"; 55 | } 56 | 57 | int main(int argc, char** argv) { 58 | tamer::initialize(); 59 | if (argc == 1 || (argc > 1 && strcmp(argv[1], "preevent") == 0)) { 60 | #if !TAMER_HAVE_PREEVENT 61 | std::cerr << "preevent<> not supported (need C++11)\n"; 62 | #else 63 | function_preevent(); 64 | #endif 65 | } else if (argc > 1 && strcmp(argv[1], "event") == 0) 66 | function_event(); 67 | else 68 | std::cerr << "Usage: t08 [preevent | event]\n"; 69 | tamer::loop(); 70 | tamer::cleanup(); 71 | } 72 | -------------------------------------------------------------------------------- /test/t08.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Test that preevents behave like events. This is also a benchmarking program. 3 | 4 | %script 5 | $rundir/test/t08 event 2>&1 6 | $rundir/test/t08 preevent 2>&1 7 | 8 | %stdout -a 9 | It happened 10 | preevent<> not supported (need C++11) 11 | 12 | %stdout -a 13 | It happened 14 | It happened 15 | -------------------------------------------------------------------------------- /test/t09.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2013, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #undef TAMER_DEBUG 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | tamed void readit(tamer::fd fd) { 25 | tvars { char buf[1024]; size_t x; int ret; } 26 | twait { fd.read(buf, sizeof(buf), x, make_event(ret)); } 27 | if (ret >= 0) 28 | std::cout << ret; 29 | else 30 | std::cout << strerror(-ret); 31 | std::cout << " returned, " << x << " bytes read\n"; 32 | } 33 | 34 | int main(int, char**) { 35 | tamer::initialize(); 36 | tamer::fd fr, fw; 37 | tamer::fd::pipe(fr, fw); 38 | readit(fr); 39 | fr.close(); 40 | tamer::loop(); 41 | tamer::cleanup(); 42 | } 43 | -------------------------------------------------------------------------------- /test/t09.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check that tamer can recover from closed file descriptors. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t09 6 | 7 | %stdout 8 | Operation cancel{{l?}}ed returned, 0 bytes read 9 | -------------------------------------------------------------------------------- /test/t10.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2013, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #undef TAMER_DEBUG 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | size_t npass = 0; 24 | 25 | tamed void passoff(tamer::fd& r, tamer::fd& w, int n) { 26 | tvars { char c; size_t x; int ret; } 27 | if (!(r && w)) { 28 | std::cerr << "Error: pipe " << n << " or thereabouts failed\n"; 29 | assert(r && w); 30 | } 31 | while (true) { 32 | fprintf(stderr, "pipe %d waits\n", n); 33 | twait { r.read(&c, 1, x, make_event(ret)); } 34 | fprintf(stderr, "pipe %d read %zd\n", n, x); 35 | if (x) { 36 | ++npass; 37 | twait { w.write(&c, 1, x, make_event(ret)); } 38 | fprintf(stderr, "pipe %d wrote %zd\n", n, x); 39 | } 40 | } 41 | } 42 | 43 | tamed void writeit(tamer::fd& w) { 44 | tvars { char c = 'A'; size_t x; int ret; } 45 | fprintf(stderr, "pipe 1 prepares\n"); 46 | twait { w.write(&c, 1, x, make_event(ret)); } 47 | fprintf(stderr, "pipe 1 wrote %zd\n", x); 48 | } 49 | 50 | tamed void readandexit(tamer::fd& r, size_t expected_npass) { 51 | tvars { char c; size_t x; int ret; } 52 | twait { r.read(&c, 1, x, make_event(ret)); } 53 | if (npass == expected_npass) 54 | std::cout << "GOOD: Got character " << c << " after " << npass << " passes\n"; 55 | else 56 | std::cout << "BAD: Got character " << c << " after " << npass << "!=" 57 | << expected_npass << " passes\n"; 58 | exit(0); 59 | } 60 | 61 | int main(int argc, char** argv) { 62 | tamer::initialize(); 63 | int n = 0, max_n = tamer::fd::open_limit(510) - 10; 64 | if (argc == 2) 65 | n = strtol(argv[1], 0, 10) & ~1; 66 | if (n <= 0 || n >= max_n) 67 | n = max_n & ~1; 68 | tamer::fd* fds = new tamer::fd[n]; 69 | for (int i = 0; i < n; i += 2) 70 | tamer::fd::pipe(fds[i], fds[i+1]); 71 | for (int i = 0; i < n - 2; i += 2) 72 | passoff(fds[i], fds[i+3], i); 73 | writeit(fds[1]); 74 | readandexit(fds[n - 2], n / 2 - 1); 75 | tamer::loop(); 76 | tamer::cleanup(); 77 | } 78 | -------------------------------------------------------------------------------- /test/t10.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check large numbers of file descriptors 3 | 4 | %script 5 | $VALGRIND $rundir/test/t10 6 | 7 | %stdout 8 | GOOD: Got character A after {{\d+}} passes 9 | -------------------------------------------------------------------------------- /test/t11.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2007, Eddie Kohler 3 | * Copyright (c) 2007, Regents of the University of California 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a 6 | * copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, subject to the conditions 8 | * listed in the Tamer LICENSE file. These conditions include: you must 9 | * preserve this copyright notice, and you cannot mention the copyright 10 | * holders in advertising related to the Software without their permission. 11 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 12 | * notice is a summary of the Tamer LICENSE file; the license in that file is 13 | * legally binding. 14 | */ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | // Expected output: 24 | // A (60ms pass) 25 | // BX (40ms pass) 26 | // A' 27 | // B (250ms pass) 28 | // E 29 | // F 30 | 31 | static tamer::mutex m; 32 | static int x = 0; 33 | 34 | tamed void f1() { 35 | twait { m.acquire(make_event()); } 36 | printf("A\n"); 37 | assert(++x == 1); 38 | twait { tamer::at_delay_msec(100, make_event()); } 39 | printf("A'\n"); 40 | assert(++x == 3); 41 | m.release(); 42 | } 43 | 44 | tamed void f2() { 45 | twait { tamer::at_delay_msec(50, make_event()); } 46 | twait { m.acquire_shared(make_event()); } 47 | printf("B\n"); 48 | assert(++x == 4); 49 | twait { 50 | tamer::at_delay_msec(250, make_event()); 51 | } 52 | m.release_shared(); 53 | printf("E\n"); 54 | assert(++x == 5); 55 | } 56 | 57 | tamed void f3() { 58 | tvars { int outcome; } 59 | twait { tamer::at_delay_msec(50, make_event()); } 60 | twait { m.acquire_shared(tamer::with_timeout_msec(10, make_event(), outcome)); } 61 | if (outcome < 0) { 62 | printf("BX\n"); 63 | assert(++x == 2); 64 | } else { 65 | printf("B'\n"); 66 | x += 10; 67 | twait { tamer::at_delay_msec(10, make_event()); } 68 | printf("C\n"); 69 | x += 10; 70 | m.release_shared(); 71 | printf("D\n"); 72 | x += 10; 73 | assert(0); 74 | } 75 | } 76 | 77 | tamed void f4() { 78 | tvars { int outcome; } 79 | twait { tamer::at_delay_msec(100, make_event()); } 80 | twait { m.acquire(tamer::with_timeout_msec(1000, make_event(), outcome)); } 81 | //twait { m.acquire(make_event()); } 82 | if (outcome < 0) { 83 | printf("FX %d %s\n", outcome, strerror(-outcome)); 84 | x += 20; 85 | assert(0); 86 | } else { 87 | printf("F\n"); 88 | assert(++x == 6); 89 | } 90 | m.release(); 91 | } 92 | 93 | int main(int, char **) { 94 | tamer::initialize(); 95 | f1(); 96 | f2(); 97 | f3(); 98 | f4(); 99 | tamer::loop(); 100 | tamer::cleanup(); 101 | } 102 | -------------------------------------------------------------------------------- /test/t11.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check the Tamer lock subsystem 3 | 4 | %script 5 | $VALGRIND $rundir/test/t11 6 | 7 | %stdout 8 | A 9 | BX 10 | A' 11 | B 12 | E 13 | F 14 | -------------------------------------------------------------------------------- /test/t12.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2007-2013, Eddie Kohler 3 | * Copyright (c) 2007, Regents of the University of California 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a 6 | * copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, subject to the conditions 8 | * listed in the Tamer LICENSE file. These conditions include: you must 9 | * preserve this copyright notice, and you cannot mention the copyright 10 | * holders in advertising related to the Software without their permission. 11 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 12 | * notice is a summary of the Tamer LICENSE file; the license in that file is 13 | * legally binding. 14 | */ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | using namespace tamer; 21 | 22 | void f(event<>) { 23 | } 24 | 25 | tamed void test_error() { 26 | twait { f(make_event()); } 27 | } 28 | 29 | int main(int, char **) { 30 | tamer::initialize(); 31 | test_error(); 32 | tamer::loop(); 33 | tamer::cleanup(); 34 | } 35 | -------------------------------------------------------------------------------- /test/t12.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check error reporting for leaked events 3 | 4 | %script 5 | $VALGRIND $rundir/test/t12 6 | 7 | %stderr -a 8 | tamer: dropping last reference to active event 9 | 10 | %stderr -a 11 | tamer: dropping last reference to active event 12 | {{tamer: .*t12\.tcc:26: event was created here}} 13 | 14 | %ignore 15 | {{^==\d+==.*}} 16 | -------------------------------------------------------------------------------- /test/t13.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2007, Eddie Kohler 3 | * Copyright (c) 2007, Regents of the University of California 4 | * 5 | * Permission is hereby granted, free of charge, to any person obtaining a 6 | * copy of this software and associated documentation files (the "Software"), 7 | * to deal in the Software without restriction, subject to the conditions 8 | * listed in the Tamer LICENSE file. These conditions include: you must 9 | * preserve this copyright notice, and you cannot mention the copyright 10 | * holders in advertising related to the Software without their permission. 11 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 12 | * notice is a summary of the Tamer LICENSE file; the license in that file is 13 | * legally binding. 14 | */ 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | using namespace tamer; 22 | 23 | tamer::mutex m; 24 | 25 | tamed void exclusive(int which) { 26 | tvars { int ret = 0; } 27 | if (which == 4 && 0) 28 | twait { m.acquire(with_timeout_msec(120, make_event(), ret)); } 29 | else 30 | twait { m.acquire(make_event()); } 31 | if (ret >= 0) { 32 | printf("%d: acquired\n", which); 33 | twait { tamer::at_delay_msec(100, make_event()); } 34 | m.release(); 35 | printf("%d: released\n", which); 36 | } else 37 | printf("%d: canceled\n", which); 38 | } 39 | 40 | tamed void shared(int which) { 41 | twait { m.acquire_shared(make_event()); } 42 | printf("%d: acquired shared\n", which); 43 | twait { tamer::at_delay_msec(100, make_event()); } 44 | m.release_shared(); 45 | printf("%d: released shared\n", which); 46 | } 47 | 48 | int main(int, char *[]) { 49 | tamer::initialize(); 50 | exclusive(1); 51 | shared(2); 52 | shared(3); 53 | exclusive(4); 54 | shared(5); 55 | tamer::loop(); 56 | tamer::cleanup(); 57 | } 58 | -------------------------------------------------------------------------------- /test/t13.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check the Tamer lock subsystem 3 | 4 | %script 5 | $VALGRIND $rundir/test/t13 6 | 7 | %stdout 8 | 1: acquired 9 | 1: released 10 | 2: acquired shared 11 | 3: acquired shared 12 | 2: released shared 13 | 3: released shared 14 | 4: acquired 15 | 4: released 16 | 5: acquired shared 17 | 5: released shared 18 | -------------------------------------------------------------------------------- /test/t14.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2013, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | using namespace tamer; 23 | 24 | tamed void child(struct sockaddr_in* saddr, socklen_t saddr_len) { 25 | tamed { 26 | tamer::fd cfd; 27 | int ret; 28 | tamer::buffer buf; 29 | std::string str; 30 | int n = 0; 31 | } 32 | cfd = tamer::fd::socket(AF_INET, SOCK_STREAM, 0); 33 | twait { cfd.connect((struct sockaddr*) saddr, saddr_len, make_event(ret)); } 34 | while (cfd && n < 12) { 35 | ++n; 36 | if (n <= 6) { 37 | twait { buf.take_until(cfd, '\n', 1024, str, make_event(ret)); } 38 | assert(ret == 0); 39 | str = "Ret " + str; 40 | if (n == 6) { 41 | int r = cfd.shutdown(SHUT_RD); 42 | assert(r == 0); 43 | } 44 | } else { 45 | twait { tamer::at_delay_msec(1, make_event()); } 46 | str = "Heh\n"; 47 | } 48 | twait { cfd.write(str, make_event(ret)); } 49 | if (ret != 0) { 50 | printf("CW #%d error %s\n", n, strerror(-ret)); 51 | } 52 | assert(ret == 0); 53 | } 54 | cfd.shutdown(SHUT_WR); 55 | twait { tamer::at_delay(2, make_event()); } 56 | cfd.close(); 57 | } 58 | 59 | tamed void parent(tamer::fd& listenfd) { 60 | tvars { 61 | tamer::fd cfd; 62 | int ret; 63 | tamer::buffer buf; 64 | std::string str; 65 | size_t nwritten; 66 | int write_rounds = 0; 67 | int wret = 0; 68 | } 69 | twait { listenfd.accept(make_event(cfd)); } 70 | while (cfd) { 71 | if (wret == 0) { 72 | { 73 | char xbuf[100]; 74 | snprintf(xbuf, sizeof(xbuf), "Hello %d\n", write_rounds); 75 | str = xbuf; 76 | } 77 | twait { cfd.write(str, nwritten, make_event(wret)); } 78 | if (wret == 0 && nwritten == str.length()) { 79 | ++write_rounds; 80 | if (write_rounds <= 6) { 81 | printf("W #%d 0: %s", write_rounds, str.c_str()); 82 | } 83 | } else { 84 | if (wret == 0) { 85 | wret = -ECANCELED; 86 | } 87 | printf("W #%d error %s\n", write_rounds, strerror(-wret)); 88 | } 89 | } 90 | twait { buf.take_until(cfd, '\n', 1024, str, make_event(ret)); } 91 | if (ret != 0) { 92 | printf("R #%d error %s\n", write_rounds, strerror(-ret)); 93 | break; 94 | } else if (str.length()) { 95 | printf("R #%d %d: %s", write_rounds, ret, str.c_str()); 96 | } else { 97 | printf("EOF\n"); 98 | } 99 | } 100 | } 101 | 102 | int main(int, char *[]) { 103 | tamer::initialize(); 104 | signal(SIGPIPE, SIG_IGN); 105 | 106 | tamer::fd listenfd = tamer::tcp_listen(0); 107 | assert(listenfd); 108 | struct sockaddr_in saddr; 109 | socklen_t saddr_len = sizeof(saddr); 110 | int r = getsockname(listenfd.fdnum(), (struct sockaddr*) &saddr, &saddr_len); 111 | assert(r == 0); 112 | 113 | pid_t p = fork(); 114 | if (p != 0) { 115 | parent(listenfd); 116 | } else { 117 | listenfd.close(); 118 | child(&saddr, saddr_len); 119 | } 120 | 121 | tamer::loop(); 122 | tamer::cleanup(); 123 | if (p != 0) { 124 | kill(p, 9); 125 | printf("Done\n"); 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /test/t14.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check shutdown() and close() in client/server 3 | 4 | %script 5 | $VALGRIND $rundir/test/t14 6 | 7 | %stdout -a 8 | W #1 0: Hello 0 9 | R #1 0: Ret Hello 0 10 | W #2 0: Hello 1 11 | R #2 0: Ret Hello 1 12 | W #3 0: Hello 2 13 | R #3 0: Ret Hello 2 14 | W #4 0: Hello 3 15 | R #4 0: Ret Hello 3 16 | W #5 0: Hello 4 17 | R #5 0: Ret Hello 4 18 | W #6 0: Hello 5 19 | R #6 0: Ret Hello 5 20 | R #7 0: Heh 21 | R #8 0: Heh 22 | R #9 0: Heh 23 | R #10 0: Heh 24 | R #11 0: Heh 25 | R #12 0: Heh 26 | R #13 error {{Broken pipe|Connection reset by peer}} 27 | Done 28 | -------------------------------------------------------------------------------- /test/t15.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2014, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | using namespace tamer; 20 | 21 | tamed void child(std::vector ary, tamer::event<> done) { 22 | tvars { std::vector x(ary.size()); } 23 | assert(ary.size() == 3); 24 | assert(x.size() == 3); 25 | twait { tamer::at_delay(0.1, make_event()); } 26 | assert(ary.size() == 3); 27 | assert(x.size() == 3); 28 | assert(ary[0] == 69); 29 | assert(ary[1] == 70); 30 | assert(ary[2] == 260); 31 | done(); 32 | } 33 | 34 | tamed void f() { 35 | tvars { std::vector x; } 36 | x.push_back(69); 37 | x.push_back(70); 38 | x.push_back(260); 39 | twait { 40 | child(x, make_event()); 41 | x.clear(); 42 | } 43 | assert(x.size() == 0); 44 | } 45 | 46 | int main(int, char *[]) { 47 | tamer::initialize(); 48 | f(); 49 | tamer::loop(); 50 | tamer::cleanup(); 51 | printf("All OK\n"); 52 | } 53 | -------------------------------------------------------------------------------- /test/t15.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check correctness of closure variable initialization 3 | 4 | %script 5 | $VALGRIND $rundir/test/t15 6 | 7 | %stdout -a 8 | All OK 9 | -------------------------------------------------------------------------------- /test/t16.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2013, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #undef TAMER_DEBUG 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | tamed void readit(tamer::fd fd) { 25 | tvars { char buf[1024]; size_t x; int ret; } 26 | twait { fd.read(buf, sizeof(buf), x, make_event(ret)); } 27 | std::cout << ret << " returned, " << x << " bytes read\n"; 28 | } 29 | 30 | tamed void timeit() { 31 | twait { tamer::at_delay(0.5, make_event()); } 32 | } 33 | 34 | tamed void asapit() { 35 | twait { tamer::at_asap(make_event()); } 36 | } 37 | 38 | tamed void printit(tamer::fd& wfd) { 39 | twait { tamer::at_delay(0.1, make_event()); } 40 | asapit(); 41 | { 42 | std::vector x; 43 | tamer::driver::main->blocked_locations(x); 44 | for (size_t i = 0; i != x.size(); ++i) 45 | std::cout << x[i] << std::endl; 46 | } 47 | wfd.close(); 48 | } 49 | 50 | int main(int, char**) { 51 | tamer::initialize(); 52 | tamer::fd fr, fw; 53 | tamer::fd::pipe(fr, fw); 54 | readit(fr); 55 | timeit(); 56 | asapit(); 57 | printit(fw); 58 | tamer::loop(); 59 | tamer::cleanup(); 60 | } 61 | -------------------------------------------------------------------------------- /test/t16.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check tamer blocked rendezvous list. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t16 | sed -e 's/.*\///' | sort 6 | 7 | %stdout 8 | 0 returned, 0 bytes read 9 | fd.tcc:{{\d+}} 10 | t16.tcc:26 11 | t16.tcc:31 12 | t16.tcc:35 13 | -------------------------------------------------------------------------------- /test/t17.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2013, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #undef TAMER_DEBUG 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | tamed void readit(tamer::fd fd) { 25 | tvars { char buf[1024]; size_t x; int ret; } 26 | twait [std::string("READING SOMETHING", 10) + " OR OTHER"] { 27 | fd.read(buf, sizeof(buf), x, make_event(ret)); 28 | } 29 | std::cout << ret << " returned, " << x << " bytes read\n"; 30 | } 31 | 32 | tamed void timeit() { 33 | twait ["HELLO"] { tamer::at_delay(0.5, make_event()); } 34 | } 35 | 36 | tamed void asapit() { 37 | twait { tamer::at_asap(make_event()); } 38 | } 39 | 40 | tamed void printit(tamer::fd& wfd) { 41 | twait { tamer::at_delay(0.1, make_event()); } 42 | asapit(); 43 | { 44 | std::vector x; 45 | tamer::driver::main->blocked_locations(x); 46 | for (size_t i = 0; i != x.size(); ++i) 47 | std::cout << x[i] << std::endl; 48 | } 49 | wfd.close(); 50 | } 51 | 52 | int main(int, char**) { 53 | tamer::initialize(); 54 | tamer::fd fr, fw; 55 | tamer::fd::pipe(fr, fw); 56 | readit(fr); 57 | timeit(); 58 | asapit(); 59 | printit(fw); 60 | tamer::loop(); 61 | tamer::cleanup(); 62 | } 63 | -------------------------------------------------------------------------------- /test/t17.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check tamer blocked rendezvous list. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t17 | sed -e 's/.*\///' | sort 6 | 7 | %stdout 8 | 0 returned, 0 bytes read 9 | fd.tcc:{{\d+}} 10 | t17.tcc:28 READING SO OR OTHER 11 | t17.tcc:33 HELLO 12 | t17.tcc:37 13 | -------------------------------------------------------------------------------- /test/t18.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2014, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #undef TAMER_DEBUG 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | using tamer::event; 24 | 25 | tamed void f(event<> e) { 26 | std::cout << "f\n"; 27 | e(); 28 | } 29 | 30 | 31 | tamed template 32 | void tf(T x, event<> e) { 33 | std::cout << "tf " << x << "\n"; 34 | e(); 35 | } 36 | 37 | 38 | class klass { 39 | public: 40 | tamed void f(event<> e); 41 | tamed template void tf(T x, event<> e); 42 | }; 43 | 44 | tamed void klass::f(event<> e) { 45 | std::cout << "klass f\n"; 46 | e(); 47 | } 48 | 49 | tamed template void klass::tf(T x, event<> e) { 50 | std::cout << "klass tf " << x << std::endl; 51 | e(); 52 | } 53 | 54 | 55 | template class tklass { 56 | public: 57 | tklass(T x) : x_(x) {} 58 | tamed void f(event<> e); 59 | tamed void g(event<> e); 60 | tamed template void tf(U x, event<> e); 61 | T x_; 62 | }; 63 | 64 | tamed template void tklass::f(event<> e) { 65 | std::cout << "tklass f " << x_ << "\n"; 66 | e(); 67 | } 68 | 69 | tamed template void tklass::g(event<> e) { 70 | tamed { T y = x_; } 71 | std::cout << "tklass g " << y << "\n"; 72 | e(); 73 | } 74 | 75 | tamed template template 76 | void tklass::tf(U x, event<> e) { 77 | std::cout << "tklass tf " << x_ << " " << x << std::endl; 78 | e(); 79 | } 80 | 81 | 82 | tamed void run() { 83 | tvars { klass k; tklass tk(2); } 84 | twait { f(make_event()); } 85 | twait { tf(1, make_event()); } 86 | twait { tf("Another one", make_event()); } 87 | twait { k.f(make_event()); } 88 | twait { tk.f(make_event()); } 89 | twait { k.tf(1, make_event()); } 90 | twait { k.tf("Another one", make_event()); } 91 | twait { tk.tf(1, make_event()); } 92 | twait { tk.tf("Another one", make_event()); } 93 | twait { tk.g(make_event()); } 94 | } 95 | 96 | int main(int, char**) { 97 | tamer::initialize(); 98 | run(); 99 | tamer::loop(); 100 | tamer::cleanup(); 101 | std::cout << "Done!\n"; 102 | } 103 | -------------------------------------------------------------------------------- /test/t18.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check tamed functions: member or not, template or not. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t18 6 | 7 | %stdout 8 | f 9 | tf 1 10 | tf Another one 11 | klass f 12 | tklass f 2 13 | klass tf 1 14 | klass tf Another one 15 | tklass tf 2 1 16 | tklass tf 2 Another one 17 | tklass g 2 18 | Done! 19 | -------------------------------------------------------------------------------- /test/t19.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2014, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #undef TAMER_DEBUG 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | using tamer::event; 24 | 25 | tamed void run() { 26 | tamed { std::vector v; } 27 | tamer::at_delay(0.1, tamer::bind(tamer::push_back_event(v), 10039)); 28 | assert(v.empty()); 29 | twait { tamer::at_delay(0.05, make_event()); } 30 | assert(v.empty()); 31 | twait { tamer::at_delay(0.06, make_event()); } 32 | assert(v.size() == 1); 33 | assert(v[0] == 10039); 34 | } 35 | 36 | tamed void run2() { 37 | tamed { int x[4]; int* it = x; } 38 | tamer::at_delay(0.02, tamer::bind(tamer::output_event(it), 2)); 39 | tamer::at_delay(0.03, tamer::bind(tamer::output_event(it), 3)); 40 | tamer::at_delay(0.01, tamer::bind(tamer::output_event(it), 1)); 41 | assert(it == x); 42 | twait { tamer::at_delay(0.05, make_event()); } 43 | assert(it == x + 3 && x[0] == 1 && x[1] == 2 && x[2] == 3); 44 | } 45 | 46 | int main(int, char**) { 47 | tamer::initialize(); 48 | run(); 49 | run2(); 50 | tamer::loop(); 51 | tamer::cleanup(); 52 | std::cout << "OK!\n"; 53 | } 54 | -------------------------------------------------------------------------------- /test/t19.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check push_back_event. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t19 6 | 7 | %stdout 8 | OK! 9 | -------------------------------------------------------------------------------- /test/t20.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2014, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #undef TAMER_DEBUG 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | using tamer::event; 24 | 25 | tamed void run() { 26 | tamed { std::string test[1024]; } 27 | for (int i = 0; i != 1024; ++i) { 28 | test[i] = std::to_string(i); 29 | } 30 | twait { tamer::at_delay(0.01, make_event()); } 31 | std::cout << test[1023] << std::endl; 32 | } 33 | 34 | tamed void run2(std::string x[4]) { 35 | twait { tamer::at_delay(0.02, make_event()); } 36 | std::cout << x[3] << std::endl; 37 | } 38 | 39 | tamed void run3() { 40 | tamed { std::string test[1024][1024]; } 41 | for (int i = 0; i != 1024; ++i) { 42 | test[i][i] = std::to_string(i); 43 | } 44 | twait { tamer::at_delay(0.03, make_event()); } 45 | std::cout << test[1023][1023] << std::endl; 46 | } 47 | 48 | tamed void run4(std::string x[3][2]) { 49 | twait { tamer::at_delay(0.04, make_event()); } 50 | std::cout << x[2][1] << std::endl; 51 | } 52 | 53 | int main(int, char**) { 54 | std::string x[4] = {"", "a", "b", "c"}; 55 | std::string x2[3][2] = {{"aa", "bb"}, {"cc", "dd"}, {"ee", "ff"}}; 56 | tamer::initialize(); 57 | run(); 58 | run2(x); 59 | run3(); 60 | run4(x2); 61 | tamer::loop(); 62 | tamer::cleanup(); 63 | std::cout << "OK!\n"; 64 | } 65 | -------------------------------------------------------------------------------- /test/t20.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check array arguments and tvars. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t20 6 | 7 | %stdout 8 | 1023 9 | c 10 | 1023 11 | ff 12 | OK! 13 | -------------------------------------------------------------------------------- /test/t21.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2014, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #undef TAMER_DEBUG 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | using tamer::event; 25 | using tamer::channel; 26 | 27 | tamed void take(channel& c) { 28 | tamed { int i, x; } 29 | for (i = 0; i != 4; ++i) { 30 | twait { c.pop_front(make_event(x)); } 31 | std::cout << i << " " << x << "\n"; 32 | } 33 | } 34 | 35 | tamed void put(channel& c) { 36 | tamed { int i; } 37 | for (i = 0; i != 3; ++i) { 38 | c.push_back(i); 39 | std::cout << "block\n"; 40 | twait { tamer::at_delay(0.01, make_event()); } 41 | } 42 | } 43 | 44 | int main(int, char**) { 45 | channel c; 46 | tamer::initialize(); 47 | c.push_back(-1); 48 | take(c); 49 | put(c); 50 | tamer::loop(); 51 | tamer::cleanup(); 52 | std::cout << "OK!\n"; 53 | } 54 | -------------------------------------------------------------------------------- /test/t21.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check tamer::channel. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t21 6 | 7 | %stdout 8 | 0 -1 9 | block 10 | 1 0 11 | block 12 | 2 1 13 | block 14 | 3 2 15 | OK! 16 | -------------------------------------------------------------------------------- /test/t22.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2014, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #undef TAMER_DEBUG 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | using tamer::event; 26 | using tamer::channel; 27 | 28 | std::ostream& operator<<(std::ostream& str, timeval x) { 29 | char buf[40]; 30 | int len = snprintf(buf, sizeof(buf), "%ld.%06ld", (long) x.tv_sec, (long) x.tv_usec); 31 | str.write(buf, len); 32 | return str; 33 | } 34 | 35 | tamed void f(tamer::fd fd) { 36 | tamed { char buf[40]; size_t len; } 37 | std::cout << tamer::recent() << "\n"; 38 | twait { tamer::at_delay(100, make_event()); } 39 | std::cout << tamer::recent() << "\n"; 40 | twait { fd.read(buf, 20, len, tamer::add_timeout(100, make_event())); } 41 | std::cout << len << " "; 42 | std::cout.write(buf, len); 43 | std::cout << "\n" << tamer::recent() << "\n"; 44 | } 45 | 46 | int main(int, char**) { 47 | tamer::initialize(); 48 | tamer::set_time_type(tamer::time_virtual); 49 | tamer::fd::make_nonblocking(0); 50 | f(tamer::fd(0)); 51 | tamer::loop(); 52 | tamer::cleanup(); 53 | std::cout << "OK!\n"; 54 | } 55 | -------------------------------------------------------------------------------- /test/t22.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check tamer virtual time. 3 | 4 | %script 5 | fsleep () { 6 | perl -e "select(undef,undef,undef,$1)" 7 | } 8 | 9 | x=`perl -e "print time"` 10 | (echo foo; fsleep 0.2; echo crap) | 11 | (fsleep 0.1; $VALGRIND $rundir/test/t22) 12 | y=`perl -e "print time"` 13 | echo delta $(($y - $x)) 14 | 15 | %stdout 16 | 1000000000.0000{{\d+}} 17 | 1000000100.0000{{\d+}} 18 | 4 foo 19 | 1000000200.0000{{\d+}} 20 | OK! 21 | delta {{0|1}} 22 | 23 | %ignore 24 | {{^==\d+==.*}} 25 | -------------------------------------------------------------------------------- /test/t23.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2014, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #undef TAMER_DEBUG 16 | #include 17 | #include 18 | 19 | tamed void f(double x, tamer::event done) { 20 | twait { tamer::at_delay(x, make_event()); } 21 | done(x > 0.1 ? "slower" : "faster"); 22 | } 23 | 24 | tamed void g(double x) { 25 | tamed { const char* str; } 26 | twait { f(x, make_event(str)); } 27 | printf("%g: %s\n", x, str); 28 | } 29 | 30 | int main(int, char**) { 31 | tamer::initialize(); 32 | tamer::set_time_type(tamer::time_virtual); 33 | g(0.15); 34 | g(0.05); 35 | tamer::loop(); 36 | tamer::cleanup(); 37 | printf("OK!\n"); 38 | } 39 | -------------------------------------------------------------------------------- /test/t23.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check tamer::event. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t23 6 | 7 | %stdout 8 | 0.05: faster 9 | 0.15: slower 10 | OK! 11 | -------------------------------------------------------------------------------- /test/t24.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2014, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #undef TAMER_DEBUG 16 | #include 17 | #include 18 | 19 | class foo : public tamer::tamed_class { 20 | public: 21 | static int nfoos; 22 | foo() { ++nfoos; } 23 | ~foo() { --nfoos; } 24 | tamed void delay(double d); 25 | }; 26 | 27 | int foo::nfoos; 28 | 29 | tamed void foo::delay(double d) { 30 | tamed { foo fart; } 31 | twait { tamer::at_delay(d, make_event()); } 32 | printf("delay %g happened\n", d); 33 | } 34 | 35 | tamed void f() { 36 | tamed { 37 | foo f0; 38 | } 39 | f0.delay(0.1); 40 | f0.delay(0.2); 41 | f0.delay(0.3); 42 | f0.delay(0.4); 43 | twait { tamer::at_delay(0.25, make_event()); } 44 | printf("return\n"); 45 | } 46 | 47 | int main(int, char**) { 48 | tamer::initialize(); 49 | tamer::set_time_type(tamer::time_virtual); 50 | f(); 51 | tamer::loop(); 52 | tamer::cleanup(); 53 | printf("OK! %d foos\n", foo::nfoos); 54 | } 55 | -------------------------------------------------------------------------------- /test/t24.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check tamer::tamed_class. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t24 6 | 7 | %stdout 8 | delay 0.1 happened 9 | delay 0.2 happened 10 | return 11 | OK! 0 foos 12 | -------------------------------------------------------------------------------- /test/t25.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2014, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #undef TAMER_DEBUG 16 | #include 17 | #include 18 | 19 | class suicider : public tamer::tamed_class { 20 | public: 21 | suicider(int who, double destroy_after) 22 | : who_(who) { 23 | destroyer(destroy_after); 24 | } 25 | private: 26 | int who_; 27 | tamed void destroyer(double after); 28 | }; 29 | 30 | tamed void suicider::destroyer(double after) { 31 | twait { tamer::at_delay(after, make_event()); } 32 | printf("suicider %d dying\n", who_); 33 | delete this; 34 | } 35 | 36 | tamed void f() { 37 | tamed { tamer::destroy_guard g(new suicider(1, 0.2)); } 38 | printf("f @0\n"); 39 | twait { tamer::at_delay(0.11, make_event()); } 40 | printf("f @1\n"); 41 | twait { tamer::at_delay(0.11, make_event()); } 42 | printf("f @2\n"); 43 | } 44 | 45 | tamed void g() { 46 | tamed { tamer::destroy_guard guard0(new suicider(2, 0.4)), 47 | guard1(new suicider(3, 0.14)); } 48 | printf("g @0\n"); 49 | twait { tamer::at_delay(0.11, make_event()); } 50 | printf("g @1\n"); 51 | twait { tamer::at_delay(0.11, make_event()); } 52 | printf("g @2\n"); 53 | twait { tamer::at_delay(0.22, make_event()); } 54 | printf("g @3\n"); 55 | } 56 | 57 | int main(int, char**) { 58 | tamer::initialize(); 59 | tamer::set_time_type(tamer::time_virtual); 60 | f(); 61 | g(); 62 | tamer::loop(); 63 | tamer::cleanup(); 64 | printf("OK!\n"); 65 | } 66 | -------------------------------------------------------------------------------- /test/t25.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check tamer::destroy_guard. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t25 6 | 7 | %stdout 8 | f @0 9 | g @0 10 | f @1 11 | g @1 12 | suicider 3 dying 13 | suicider 1 dying 14 | suicider 2 dying 15 | OK! 16 | -------------------------------------------------------------------------------- /test/t26.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2014, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #undef TAMER_DEBUG 16 | #include 17 | #include 18 | 19 | int main(int, char**) { 20 | tamer::initialize(); 21 | tamer::set_time_type(tamer::time_virtual); 22 | 23 | tamer::event<> e[20]; 24 | tamer::rendezvous<> r; 25 | tamer::at_delay_msec(11, e[0] = r.make_event()); 26 | tamer::at_delay_msec(12, e[1] = r.make_event()); 27 | tamer::at_delay_msec(13, e[2] = r.make_event()); 28 | tamer::at_delay_msec(20, e[3] = r.make_event()); 29 | tamer::at_delay_msec(17, e[4] = r.make_event()); 30 | tamer::at_delay_msec(18, e[5] = r.make_event()); 31 | tamer::at_delay_msec(15, e[6] = r.make_event()); 32 | tamer::at_delay_msec(14, e[7] = r.make_event()); 33 | tamer::at_delay_msec(16, e[8] = r.make_event()); 34 | tamer::at_delay_msec(21, e[9] = r.make_event()); 35 | tamer::at_delay_msec(19, e[10] = r.make_event()); 36 | 37 | e[1](); 38 | e[2](); 39 | e[4](); 40 | e[5](); 41 | e[7](); 42 | 43 | tamer::at_delay_msec(4, e[11] = r.make_event()); 44 | 45 | tamer::once(); 46 | 47 | printf("%06ld\n", (long) tamer::recent().tv_usec); 48 | assert(tamer::recent().tv_usec == 4002); 49 | 50 | tamer::loop(); 51 | tamer::cleanup(); 52 | printf("OK!\n"); 53 | } 54 | -------------------------------------------------------------------------------- /test/t26.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check stupid bug in timer heap. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t26 6 | 7 | %stdout 8 | 004002 9 | OK! 10 | -------------------------------------------------------------------------------- /test/t27.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2014, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #undef TAMER_DEBUG 16 | #include 17 | #include 18 | 19 | class foo : public tamer::tamed_class { 20 | public: 21 | static int nfoos; 22 | foo() { ++nfoos; } 23 | ~foo() { --nfoos; } 24 | tamed virtual void delay(double d); 25 | }; 26 | 27 | class bar : public foo { 28 | tamed virtual void delay(double d); 29 | }; 30 | 31 | int foo::nfoos; 32 | 33 | tamed void foo::delay(double d) { 34 | tamed { foo fart; } 35 | twait { tamer::at_delay(d, make_event()); } 36 | printf("foo delay %g happened\n", d); 37 | } 38 | 39 | tamed void bar::delay(double d) { 40 | tamed { foo fart; } 41 | twait { tamer::at_delay(d, make_event()); } 42 | printf("bar delay %g happened\n", d); 43 | } 44 | 45 | tamed void f(foo* f0, foo* f1) { 46 | f0->delay(0.1); 47 | f1->delay(0.2); 48 | f0->delay(0.3); 49 | f1->delay(0.4); 50 | twait { tamer::at_delay(0.25, make_event()); } 51 | printf("return\n"); 52 | } 53 | 54 | int main(int, char**) { 55 | foo f0; 56 | bar b0; 57 | tamer::initialize(); 58 | tamer::set_time_type(tamer::time_virtual); 59 | f(&f0, &b0); 60 | tamer::loop(); 61 | tamer::cleanup(); 62 | printf("OK! %d foos\n", foo::nfoos); 63 | } 64 | -------------------------------------------------------------------------------- /test/t27.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check virtual. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t27 6 | 7 | %stdout 8 | foo delay 0.1 happened 9 | bar delay 0.2 happened 10 | return 11 | foo delay 0.3 happened 12 | bar delay 0.4 happened 13 | OK! 2 foos 14 | -------------------------------------------------------------------------------- /test/t28.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2014, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | struct A { 24 | tamed template 25 | void doit(F func, tamer::event<> done); 26 | 27 | tamed void helper(int foo, tamer::event<> done); 28 | }; 29 | 30 | struct B { 31 | tamed void passit(A* a, tamer::event<> done); 32 | }; 33 | 34 | 35 | tamed template 36 | void A::doit(F func, tamer::event<> done) { 37 | twait { helper(func(27), make_event()); } 38 | done(); 39 | } 40 | 41 | tamed void A::helper(int foo, tamer::event<> done) { 42 | std::cout << "in helper " << foo << std::endl; 43 | done(); 44 | } 45 | 46 | #if TAMER_HAVE_CXX_LAMBDAS 47 | tamed void B::passit(A* a, tamer::event<> done) { 48 | twait { a->doit([=](int b){ return b * 2; }, make_event()); } 49 | done(); 50 | } 51 | #else 52 | tamed void B::passit(A* a, tamer::event<> done) { 53 | printf("no c++11 lambda support\n"); 54 | done(); 55 | } 56 | #endif 57 | 58 | 59 | tamed void function() { 60 | tvars { 61 | A a; 62 | B b; 63 | } 64 | 65 | twait { b.passit(&a, make_event()); } 66 | } 67 | 68 | int main(int, char**) { 69 | tamer::initialize(); 70 | function(); 71 | tamer::loop(); 72 | tamer::cleanup(); 73 | } 74 | -------------------------------------------------------------------------------- /test/t28.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check lambdas. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t28 6 | 7 | %stdout -a 8 | in helper 54 9 | 10 | %stdout -a 11 | no c++11 lambda support 12 | -------------------------------------------------------------------------------- /test/t29.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2014, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include "config.h" 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | int global_x = 19324; 24 | 25 | tamed void f(tamer::event done) { 26 | tvars { 27 | int& x = global_x; 28 | } 29 | done(x); 30 | } 31 | 32 | tamed void g() { 33 | tvars { int x; } 34 | twait { f(tamer::make_event(x)); } 35 | fprintf(stdout, "Got %d\n", x); 36 | } 37 | 38 | int main(int, char**) { 39 | tamer::initialize(); 40 | g(); 41 | tamer::loop(); 42 | tamer::cleanup(); 43 | } 44 | -------------------------------------------------------------------------------- /test/t29.testie: -------------------------------------------------------------------------------- 1 | %info 2 | Check reference correctness. 3 | 4 | %script 5 | $VALGRIND $rundir/test/t29 6 | 7 | %stdout 8 | Got 19324 9 | -------------------------------------------------------------------------------- /test/t30.tcc: -------------------------------------------------------------------------------- 1 | // -*- mode: c++ -*- 2 | /* Copyright (c) 2023, Eddie Kohler 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, subject to the conditions 7 | * listed in the Tamer LICENSE file. These conditions include: you must 8 | * preserve this copyright notice, and you cannot mention the copyright 9 | * holders in advertising related to the Software without their permission. 10 | * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This 11 | * notice is a summary of the Tamer LICENSE file; the license in that file is 12 | * legally binding. 13 | */ 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | using namespace tamer; 21 | static double dstart; 22 | 23 | tamed void child(struct sockaddr_in* saddr, socklen_t saddr_len) { 24 | tamed { 25 | tamer::fd cfd; 26 | int ret; 27 | } 28 | cfd = tamer::fd::socket(AF_INET, SOCK_STREAM, 0); 29 | twait { 30 | cfd.connect((struct sockaddr*) saddr, saddr_len, make_event(ret)); 31 | } 32 | twait { tamer::at_delay_msec(100, make_event()); } 33 | twait { cfd.write("1", make_event(ret)); } 34 | twait { tamer::at_delay_msec(100, make_event()); } 35 | cfd.shutdown(SHUT_WR); 36 | twait { tamer::at_delay_msec(100, make_event()); } 37 | cfd.close(); 38 | } 39 | 40 | tamed void check_read(tamer::fd cfd) { 41 | twait { 42 | tamer::at_fd_read(cfd.fdnum(), tamer::add_timeout(1, make_event())); 43 | } 44 | printf("R %.06g\n", tamer::dnow() - dstart); 45 | } 46 | 47 | tamed void check_shutdown(tamer::fd cfd) { 48 | twait { 49 | tamer::at_fd_shutdown(cfd.fdnum(), tamer::add_timeout(1, make_event())); 50 | } 51 | printf("SD %.06g\n", tamer::dnow() - dstart); 52 | } 53 | 54 | tamed void parent(tamer::fd& listenfd) { 55 | tvars { 56 | tamer::fd cfd; 57 | } 58 | twait { listenfd.accept(make_event(cfd)); } 59 | check_read(cfd); 60 | check_shutdown(cfd); 61 | } 62 | 63 | int main(int, char *[]) { 64 | tamer::initialize(); 65 | dstart = tamer::dnow(); 66 | signal(SIGPIPE, SIG_IGN); 67 | 68 | tamer::fd listenfd = tamer::tcp_listen(0); 69 | assert(listenfd); 70 | struct sockaddr_in saddr; 71 | socklen_t saddr_len = sizeof(saddr); 72 | int r = getsockname(listenfd.fdnum(), (struct sockaddr*) &saddr, &saddr_len); 73 | assert(r == 0); 74 | 75 | pid_t p = fork(); 76 | if (p != 0) { 77 | parent(listenfd); 78 | } else { 79 | listenfd.close(); 80 | child(&saddr, saddr_len); 81 | } 82 | 83 | tamer::loop(); 84 | tamer::cleanup(); 85 | if (p != 0) { 86 | kill(p, 9); 87 | printf("Done\n"); 88 | } 89 | } 90 | --------------------------------------------------------------------------------