• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 //          Copyright Oliver Kowalke 2009.
3 // Distributed under the Boost Software License, Version 1.0.
4 //    (See accompanying file LICENSE_1_0.txt or copy at
5 //          http://www.boost.org/LICENSE_1_0.txt)
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 
10 #include <cmath>
11 #include <cstdint>
12 #include <iostream>
13 #include <sstream>
14 #include <stdexcept>
15 #include <string>
16 #include <utility>
17 
18 #include <boost/array.hpp>
19 #include <boost/assert.hpp>
20 #include <boost/test/unit_test.hpp>
21 #include <boost/utility.hpp>
22 
23 #include <boost/context/detail/config.hpp>
24 #include <boost/context/detail/fcontext.hpp>
25 
26 template< std::size_t Max, std::size_t Default, std::size_t Min >
27 class simple_stack_allocator
28 {
29 public:
maximum_stacksize()30     static std::size_t maximum_stacksize()
31     { return Max; }
32 
default_stacksize()33     static std::size_t default_stacksize()
34     { return Default; }
35 
minimum_stacksize()36     static std::size_t minimum_stacksize()
37     { return Min; }
38 
allocate(std::size_t size) const39     void * allocate( std::size_t size) const
40     {
41         BOOST_ASSERT( minimum_stacksize() <= size);
42         BOOST_ASSERT( maximum_stacksize() >= size);
43 
44         void * limit = malloc( size);
45         if ( ! limit) throw std::bad_alloc();
46 
47         return static_cast< char * >( limit) + size;
48     }
49 
deallocate(void * vp,std::size_t size) const50     void deallocate( void * vp, std::size_t size) const
51     {
52         BOOST_ASSERT( vp);
53         BOOST_ASSERT( minimum_stacksize() <= size);
54         BOOST_ASSERT( maximum_stacksize() >= size);
55 
56         void * limit = static_cast< char * >( vp) - size;
57         free( limit);
58     }
59 };
60 
61 typedef simple_stack_allocator<
62             8 * 1024 * 1024, 64 * 1024, 8 * 1024
63         >                                       stack_allocator;
64 
65 namespace ctx = boost::context::detail;
66 
67 typedef simple_stack_allocator<
68     8 * 1024 * 1024, // 8MB
69     64 * 1024, // 64kB
70     8 * 1024 // 8kB
71 >       stack_allocator;
72 
73 int value1 = 0;
74 std::string value2;
75 double value3 = 0.;
76 void * value4 = 0;
77 
f1(ctx::transfer_t t)78 void f1( ctx::transfer_t t) {
79     ++value1;
80     ctx::jump_fcontext( t.fctx, t.data);
81 }
82 
f3(ctx::transfer_t t_)83 void f3( ctx::transfer_t t_) {
84     ++value1;
85     ctx::transfer_t t = ctx::jump_fcontext( t_.fctx, 0);
86     ++value1;
87     ctx::jump_fcontext( t.fctx, t.data);
88 }
89 
f4(ctx::transfer_t t)90 void f4( ctx::transfer_t t) {
91     int i = 7;
92     ctx::jump_fcontext( t.fctx, & i);
93 }
94 
f5(ctx::transfer_t t)95 void f5( ctx::transfer_t t) {
96     ctx::jump_fcontext( t.fctx, t.data);
97 }
98 
f6(ctx::transfer_t t_)99 void f6( ctx::transfer_t t_) {
100     std::pair< int, int > data = * ( std::pair< int, int > * ) t_.data;
101     int res = data.first + data.second;
102     ctx::transfer_t t = ctx::jump_fcontext( t_.fctx, & res);
103     data = * ( std::pair< int, int > *) t.data;
104     res = data.first + data.second;
105     ctx::jump_fcontext( t.fctx, & res);
106 }
107 
f7(ctx::transfer_t t)108 void f7( ctx::transfer_t t) {
109     try {
110         throw std::runtime_error( * ( std::string *) t.data);
111     } catch ( std::runtime_error const& e) {
112         value2 = e.what();
113     }
114     ctx::jump_fcontext( t.fctx, t.data);
115 }
116 
f8(ctx::transfer_t t)117 void f8( ctx::transfer_t t) {
118     double d = * ( double *) t.data;
119     d += 3.45;
120     value3 = d;
121     ctx::jump_fcontext( t.fctx, 0);
122 }
123 
f10(ctx::transfer_t t)124 void f10( ctx::transfer_t t) {
125     value1 = 3;
126     ctx::jump_fcontext( t.fctx, 0);
127 }
128 
f9(ctx::transfer_t t)129 void f9( ctx::transfer_t t) {
130     std::cout << "f1: entered" << std::endl;
131     stack_allocator alloc;
132     void * sp = alloc.allocate( stack_allocator::default_stacksize());
133     ctx::fcontext_t ctx = ctx::make_fcontext( sp, stack_allocator::default_stacksize(), f10);
134     ctx::jump_fcontext( ctx, 0);
135     ctx::jump_fcontext( t.fctx, 0);
136 }
137 
f11(ctx::transfer_t t_)138 ctx::transfer_t f11( ctx::transfer_t t_) {
139     value4 = t_.data;
140     ctx::transfer_t t = { t_.fctx, t_.data };
141     return t;
142 }
143 
f12(ctx::transfer_t t_)144 void f12( ctx::transfer_t t_) {
145     ctx::transfer_t t = ctx::jump_fcontext( t_.fctx, t_.data);
146     value1 = * ( int *) t.data;
147     ctx::jump_fcontext( t.fctx, t.data);
148 }
149 
f13(ctx::transfer_t t)150 void f13( ctx::transfer_t t) {
151     {
152         double n1 = 0;
153         double n2 = 0;
154         sscanf("3.14 7.13", "%lf %lf", & n1, & n2);
155         BOOST_CHECK( n1 == 3.14);
156         BOOST_CHECK( n2 == 7.13);
157     }
158     {
159         int n1=0;
160         int n2=0;
161         sscanf("1 23", "%d %d", & n1, & n2);
162         BOOST_CHECK( n1 == 1);
163         BOOST_CHECK( n2 == 23);
164     }
165     {
166         int n1=0;
167         int n2=0;
168         sscanf("1 jjj 23", "%d %*[j] %d", & n1, & n2);
169         BOOST_CHECK( n1 == 1);
170         BOOST_CHECK( n2 == 23);
171     }
172     ctx::jump_fcontext( t.fctx, 0);
173 }
174 
f14(ctx::transfer_t t)175 void f14( ctx::transfer_t t) {
176     {
177         const char *fmt = "sqrt(2) = %f";
178         char buf[19];
179         snprintf( buf, sizeof( buf), fmt, std::sqrt( 2) );
180         BOOST_CHECK( 0 < sizeof( buf) );
181         BOOST_CHECK_EQUAL( std::string("sqrt(2) = 1.41"), std::string( buf, 14) );
182     }
183     {
184         std::uint64_t n = 0xbcdef1234567890;
185         const char *fmt = "0x%016llX";
186         char buf[100];
187         snprintf( buf, sizeof( buf), fmt, n);
188         BOOST_CHECK_EQUAL( std::string("0x0BCDEF1234567890"), std::string( buf, 18) );
189     }
190     ctx::jump_fcontext( t.fctx, 0);
191 }
192 
test_setup()193 void test_setup() {
194     stack_allocator alloc;
195     void * sp = alloc.allocate( stack_allocator::default_stacksize() );
196     ctx::fcontext_t ctx = ctx::make_fcontext( sp, stack_allocator::default_stacksize(), f1);
197     BOOST_CHECK( ctx);
198 	alloc.deallocate( sp, stack_allocator::default_stacksize() );
199 }
200 
test_start()201 void test_start() {
202     value1 = 0;
203     stack_allocator alloc;
204     void * sp = alloc.allocate( stack_allocator::default_stacksize() );
205     ctx::fcontext_t ctx = ctx::make_fcontext( sp, stack_allocator::default_stacksize(), f1);
206     BOOST_CHECK( ctx);
207 
208     BOOST_CHECK_EQUAL( 0, value1);
209     ctx::jump_fcontext( ctx, 0);
210     BOOST_CHECK_EQUAL( 1, value1);
211 	alloc.deallocate( sp, stack_allocator::default_stacksize() );
212 }
213 
test_jump()214 void test_jump() {
215     value1 = 0;
216     stack_allocator alloc;
217     void * sp = alloc.allocate( stack_allocator::default_stacksize() );
218     ctx::fcontext_t ctx = ctx::make_fcontext( sp, stack_allocator::default_stacksize(), f3);
219     BOOST_CHECK( ctx);
220     BOOST_CHECK_EQUAL( 0, value1);
221     ctx::transfer_t t = ctx::jump_fcontext( ctx, 0);
222     BOOST_CHECK_EQUAL( 1, value1);
223     ctx::jump_fcontext( t.fctx, 0);
224     BOOST_CHECK_EQUAL( 2, value1);
225 	alloc.deallocate( sp, stack_allocator::default_stacksize() );
226 }
227 
test_result()228 void test_result() {
229     stack_allocator alloc;
230     void * sp = alloc.allocate( stack_allocator::default_stacksize() );
231     ctx::fcontext_t ctx = ctx::make_fcontext( sp, stack_allocator::default_stacksize(), f4);
232     BOOST_CHECK( ctx);
233     ctx::transfer_t t = ctx::jump_fcontext( ctx, 0);
234     int result = * ( int *) t.data;
235     BOOST_CHECK_EQUAL( 7, result);
236 	alloc.deallocate( sp, stack_allocator::default_stacksize() );
237 }
238 
test_arg()239 void test_arg() {
240     stack_allocator alloc;
241     int i = 7;
242     void * sp = alloc.allocate( stack_allocator::default_stacksize() );
243     ctx::fcontext_t ctx = ctx::make_fcontext( sp, stack_allocator::default_stacksize(), f5);
244     BOOST_CHECK( ctx);
245     ctx::transfer_t t = ctx::jump_fcontext( ctx, & i);
246     int result = * ( int *) t.data;
247     BOOST_CHECK_EQUAL( i, result);
248 	alloc.deallocate( sp, stack_allocator::default_stacksize() );
249 }
250 
test_transfer()251 void test_transfer() {
252     stack_allocator alloc;
253     std::pair< int, int > data = std::make_pair( 3, 7);
254     void * sp = alloc.allocate( stack_allocator::default_stacksize() );
255     ctx::fcontext_t ctx = ctx::make_fcontext( sp, stack_allocator::default_stacksize(), f6);
256     BOOST_CHECK( ctx);
257     ctx::transfer_t t = ctx::jump_fcontext( ctx, & data);
258     int result = * ( int *) t.data;
259     BOOST_CHECK_EQUAL( 10, result);
260     data = std::make_pair( 7, 7);
261     t = ctx::jump_fcontext( t.fctx, & data);
262     result = * ( int *) t.data;
263     BOOST_CHECK_EQUAL( 14, result);
264 	alloc.deallocate( sp, stack_allocator::default_stacksize() );
265 }
266 
test_exception()267 void test_exception() {
268     stack_allocator alloc;
269     std::string what("hello world");
270     void * sp = alloc.allocate( stack_allocator::default_stacksize() );
271     ctx::fcontext_t ctx = ctx::make_fcontext( sp, stack_allocator::default_stacksize(), f7);
272     BOOST_CHECK( ctx);
273     ctx::jump_fcontext( ctx, & what);
274     BOOST_CHECK_EQUAL( std::string( what), value2);
275 	alloc.deallocate( sp, stack_allocator::default_stacksize() );
276 }
277 
test_fp()278 void test_fp() {
279     stack_allocator alloc;
280     double d = 7.13;
281     void * sp = alloc.allocate( stack_allocator::default_stacksize() );
282     ctx::fcontext_t ctx = ctx::make_fcontext( sp, stack_allocator::default_stacksize(), f8);
283     BOOST_CHECK( ctx);
284     ctx::jump_fcontext( ctx, & d);
285     BOOST_CHECK_EQUAL( 10.58, value3);
286 	alloc.deallocate( sp, stack_allocator::default_stacksize() );
287 }
288 
test_stacked()289 void test_stacked() {
290     value1 = 0;
291     stack_allocator alloc;
292     void * sp = alloc.allocate( stack_allocator::default_stacksize());
293     ctx::fcontext_t ctx = ctx::make_fcontext( sp, stack_allocator::default_stacksize(), f9);
294     ctx::jump_fcontext( ctx, 0);
295     BOOST_CHECK_EQUAL( 3, value1);
296 	alloc.deallocate( sp, stack_allocator::default_stacksize() );
297 }
298 
test_ontop()299 void test_ontop() {
300     value1 = 0;
301     value4 = 0;
302     stack_allocator alloc;
303     void * sp = alloc.allocate( stack_allocator::default_stacksize() );
304     ctx::fcontext_t ctx = ctx::make_fcontext( sp, stack_allocator::default_stacksize(), f12);
305     BOOST_CHECK( ctx);
306     ctx::transfer_t t = ctx::jump_fcontext( ctx, 0);
307     BOOST_CHECK_EQUAL( 0, value1);
308     BOOST_CHECK( 0 == value4);
309     int i = -3;
310     t = ctx::ontop_fcontext( t.fctx, & i, f11);
311     BOOST_CHECK_EQUAL( -3, value1);
312     BOOST_CHECK_EQUAL( & i, value4);
313     BOOST_CHECK_EQUAL( -3, * ( int *) t.data);
314     BOOST_CHECK_EQUAL( & i, ( int *) t.data);
315 	alloc.deallocate( sp, stack_allocator::default_stacksize() );
316 }
317 
test_sscanf()318 void test_sscanf() {
319     stack_allocator alloc;
320     void * sp = alloc.allocate( stack_allocator::default_stacksize() );
321     ctx::fcontext_t ctx = ctx::make_fcontext( sp, stack_allocator::default_stacksize(), f13);
322     BOOST_CHECK( ctx);
323     ctx::jump_fcontext( ctx, 0);
324 	alloc.deallocate( sp, stack_allocator::default_stacksize() );
325 }
326 
test_snprintf()327 void test_snprintf() {
328     stack_allocator alloc;
329     void * sp = alloc.allocate( stack_allocator::default_stacksize() );
330     ctx::fcontext_t ctx = ctx::make_fcontext( sp, stack_allocator::default_stacksize(), f14);
331     ctx::jump_fcontext( ctx, 0);
332 	alloc.deallocate( sp, stack_allocator::default_stacksize() );
333 }
334 
init_unit_test_suite(int,char * [])335 boost::unit_test::test_suite * init_unit_test_suite( int, char* []) {
336     boost::unit_test::test_suite * test =
337         BOOST_TEST_SUITE("Boost.Context: fcontext test suite");
338     test->add( BOOST_TEST_CASE( & test_setup) );
339     test->add( BOOST_TEST_CASE( & test_start) );
340     test->add( BOOST_TEST_CASE( & test_jump) );
341     test->add( BOOST_TEST_CASE( & test_result) );
342     test->add( BOOST_TEST_CASE( & test_arg) );
343     test->add( BOOST_TEST_CASE( & test_transfer) );
344     test->add( BOOST_TEST_CASE( & test_exception) );
345     test->add( BOOST_TEST_CASE( & test_fp) );
346     test->add( BOOST_TEST_CASE( & test_stacked) );
347     test->add( BOOST_TEST_CASE( & test_ontop) );
348     test->add( BOOST_TEST_CASE( & test_sscanf) );
349     test->add( BOOST_TEST_CASE( & test_snprintf) );
350 
351     return test;
352 }
353