aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2018-11-08 17:32:05 +0100
committerBenoit Germain <bnt.germain@gmail.com>2018-11-08 17:32:05 +0100
commit0cc1c9c9dcea5955f7dab921d9a2fff78c4e1729 (patch)
tree5c35acf11087f9b60b24599695f1d3c348ebaa25
parenta142eb1e1ee81919d10b55bb7fa2e33636098d85 (diff)
downloadlanes-0cc1c9c9dcea5955f7dab921d9a2fff78c4e1729.tar.gz
lanes-0cc1c9c9dcea5955f7dab921d9a2fff78c4e1729.tar.bz2
lanes-0cc1c9c9dcea5955f7dab921d9a2fff78c4e1729.zip
Make sure any linda operation that can raise an error won't ever leave a mutex unreleased
-rw-r--r--CHANGES4
-rw-r--r--docs/index.html2
-rw-r--r--src/keeper.c11
-rw-r--r--src/keeper.h1
-rw-r--r--src/lanes.c99
-rw-r--r--tests/deadlock.lua28
6 files changed, 101 insertions, 44 deletions
diff --git a/CHANGES b/CHANGES
index 228038b..a90358b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,5 +1,9 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 133: BGe 8-Nov-18
4 * Make sure any linda operation that can raise an error won't ever leave a mutex unreleased
5 * lane:join() now returns nil, "timeout" in case of timeout
6
3CHANGE 132: BGe 7-Nov-18 7CHANGE 132: BGe 7-Nov-18
4 * __lanesclone mechanism should actually work now 8 * __lanesclone mechanism should actually work now
5 9
diff --git a/docs/index.html b/docs/index.html
index 9c76bef..ef227c8 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -855,7 +855,7 @@
855</pre></td></tr></table> 855</pre></td></tr></table>
856 856
857<p> 857<p>
858 Waits until the lane finishes, or <tt>timeout</tt> seconds have passed. Returns <tt>nil</tt> on timeout, <tt>nil,err,stack_tbl</tt> if the lane hit an error, <tt>nil, "killed"</tt> if forcefully killed (starting with v3.3.0), or the return values of the lane. 858 Waits until the lane finishes, or <tt>timeout</tt> seconds have passed. Returns <tt>nil, "timeout"</tt> on timeout (since v3.13), <tt>nil,err,stack_tbl</tt> if the lane hit an error, <tt>nil, "killed"</tt> if forcefully killed (starting with v3.3.0), or the return values of the lane.
859 Unlike in reading the results in table fashion, errors are not propagated. 859 Unlike in reading the results in table fashion, errors are not propagated.
860</p> 860</p>
861 861
diff --git a/src/keeper.c b/src/keeper.c
index 715583b..b67bee2 100644
--- a/src/keeper.c
+++ b/src/keeper.c
@@ -188,7 +188,7 @@ static void push_table( lua_State* L, int idx_)
188 188
189int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t magic_) 189int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t magic_)
190{ 190{
191 Keeper* const K = keeper_acquire( U->keepers, magic_); 191 Keeper* const K = which_keeper( U->keepers, magic_);
192 lua_State* const KL = K ? K->L : NULL; 192 lua_State* const KL = K ? K->L : NULL;
193 if( KL == NULL) return 0; 193 if( KL == NULL) return 0;
194 STACK_GROW( KL, 4); 194 STACK_GROW( KL, 4);
@@ -233,7 +233,6 @@ int keeper_push_linda_storage( Universe* U, lua_State* L, void* ptr_, ptrdiff_t
233 STACK_END( L, 1); 233 STACK_END( L, 1);
234 lua_pop( KL, 1); // 234 lua_pop( KL, 1); //
235 STACK_END( KL, 0); 235 STACK_END( KL, 0);
236 keeper_release( K);
237 return 1; 236 return 1;
238} 237}
239 238
@@ -715,6 +714,14 @@ void init_keepers( Universe* U, lua_State* L)
715 STACK_END( L, 0); 714 STACK_END( L, 0);
716} 715}
717 716
717// should be called only when inside a keeper_acquire/keeper_release pair (see linda_protected_call)
718Keeper* which_keeper(Keepers* keepers_, ptrdiff_t magic_)
719{
720 int const nbKeepers = keepers_->nb_keepers;
721 unsigned int i = (unsigned int)((magic_ >> KEEPER_MAGIC_SHIFT) % nbKeepers);
722 return &keepers_->keeper_array[i];
723}
724
718Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_) 725Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_)
719{ 726{
720 int const nbKeepers = keepers_->nb_keepers; 727 int const nbKeepers = keepers_->nb_keepers;
diff --git a/src/keeper.h b/src/keeper.h
index 37922fb..60410da 100644
--- a/src/keeper.h
+++ b/src/keeper.h
@@ -29,6 +29,7 @@ typedef struct s_Keepers Keepers;
29void init_keepers( Universe* U, lua_State* L); 29void init_keepers( Universe* U, lua_State* L);
30void close_keepers( Universe* U, lua_State* L); 30void close_keepers( Universe* U, lua_State* L);
31 31
32Keeper* which_keeper( Keepers* keepers_, ptrdiff_t magic_);
32Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_); 33Keeper* keeper_acquire( Keepers* keepers_, ptrdiff_t magic_);
33#define KEEPER_MAGIC_SHIFT 3 34#define KEEPER_MAGIC_SHIFT 3
34void keeper_release( Keeper* K); 35void keeper_release( Keeper* K);
diff --git a/src/lanes.c b/src/lanes.c
index c3e64fb..72f9dd6 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -453,6 +453,34 @@ static void check_key_types( lua_State* L, int start_, int end_)
453 } 453 }
454} 454}
455 455
456LUAG_FUNC( linda_protected_call)
457{
458 int rc = LUA_OK;
459 struct s_Linda* linda = lua_toLinda( L, 1);
460
461 // acquire the keeper
462 Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED(linda));
463 lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK'
464 if( KL == NULL) return 0;
465
466 // retrieve the actual function to be called and move it before the arguments
467 lua_pushvalue( L, lua_upvalueindex( 1));
468 lua_insert( L, 1);
469 // do a protected call
470 rc = lua_pcall( L, lua_gettop( L) - 1, LUA_MULTRET, 0);
471
472 // release the keeper
473 keeper_release( K);
474
475 // if there was an error, forward it
476 if( rc != LUA_OK)
477 {
478 return lua_error( L);
479 }
480 // return whatever the actual operation provided
481 return lua_gettop( L);
482}
483
456/* 484/*
457* bool= linda_send( linda_ud, [timeout_secs=-1,] [linda.null,] key_num|str|bool|lightuserdata, ... ) 485* bool= linda_send( linda_ud, [timeout_secs=-1,] [linda.null,] key_num|str|bool|lightuserdata, ... )
458* 486*
@@ -514,7 +542,7 @@ LUAG_FUNC( linda_send)
514 { 542 {
515 bool_t try_again = TRUE; 543 bool_t try_again = TRUE;
516 Lane* const s = get_lane_from_registry( L); 544 Lane* const s = get_lane_from_registry( L);
517 Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); 545 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
518 lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK' 546 lua_State* KL = K ? K->L : NULL; // need to do this for 'STACK_CHECK'
519 if( KL == NULL) return 0; 547 if( KL == NULL) return 0;
520 STACK_CHECK( KL); 548 STACK_CHECK( KL);
@@ -578,10 +606,8 @@ LUAG_FUNC( linda_send)
578 } 606 }
579 } 607 }
580 STACK_END( KL, 0); 608 STACK_END( KL, 0);
581 keeper_release( K);
582 } 609 }
583 610
584 // must trigger error after keeper state has been released
585 if( pushed < 0) 611 if( pushed < 0)
586 { 612 {
587 return luaL_error( L, "tried to copy unsupported types"); 613 return luaL_error( L, "tried to copy unsupported types");
@@ -676,7 +702,7 @@ LUAG_FUNC( linda_receive)
676 { 702 {
677 bool_t try_again = TRUE; 703 bool_t try_again = TRUE;
678 Lane* const s = get_lane_from_registry( L); 704 Lane* const s = get_lane_from_registry( L);
679 Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); 705 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
680 if( K == NULL) return 0; 706 if( K == NULL) return 0;
681 for( ;;) 707 for( ;;)
682 { 708 {
@@ -735,10 +761,8 @@ LUAG_FUNC( linda_receive)
735 } 761 }
736 } 762 }
737 } 763 }
738 keeper_release( K);
739 } 764 }
740 765
741 // must trigger error after keeper state has been released
742 if( pushed < 0) 766 if( pushed < 0)
743 { 767 {
744 return luaL_error( L, "tried to copy unsupported types"); 768 return luaL_error( L, "tried to copy unsupported types");
@@ -779,8 +803,7 @@ LUAG_FUNC( linda_set)
779 check_key_types( L, 2, 2); 803 check_key_types( L, 2, 2);
780 804
781 { 805 {
782 Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); 806 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
783 if( K == NULL) return 0;
784 807
785 if( linda->simulate_cancel == CANCEL_NONE) 808 if( linda->simulate_cancel == CANCEL_NONE)
786 { 809 {
@@ -813,7 +836,6 @@ LUAG_FUNC( linda_set)
813 push_unique_key( L, CANCEL_ERROR); 836 push_unique_key( L, CANCEL_ERROR);
814 pushed = 1; 837 pushed = 1;
815 } 838 }
816 keeper_release( K);
817 } 839 }
818 840
819 // must trigger any error after keeper state has been released 841 // must trigger any error after keeper state has been released
@@ -835,10 +857,8 @@ LUAG_FUNC( linda_count)
835 check_key_types( L, 2, lua_gettop( L)); 857 check_key_types( L, 2, lua_gettop( L));
836 858
837 { 859 {
838 Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); 860 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
839 if( K == NULL) return 0;
840 pushed = keeper_call( linda->U, K->L, KEEPER_API( count), L, linda, 2); 861 pushed = keeper_call( linda->U, K->L, KEEPER_API( count), L, linda, 2);
841 keeper_release( K);
842 if( pushed < 0) 862 if( pushed < 0)
843 { 863 {
844 return luaL_error( L, "tried to count an invalid key"); 864 return luaL_error( L, "tried to count an invalid key");
@@ -864,8 +884,7 @@ LUAG_FUNC( linda_get)
864 // make sure the key is of a valid type (throws an error if not the case) 884 // make sure the key is of a valid type (throws an error if not the case)
865 check_key_types( L, 2, 2); 885 check_key_types( L, 2, 2);
866 { 886 {
867 Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); 887 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
868 if( K == NULL) return 0;
869 888
870 if( linda->simulate_cancel == CANCEL_NONE) 889 if( linda->simulate_cancel == CANCEL_NONE)
871 { 890 {
@@ -881,9 +900,7 @@ LUAG_FUNC( linda_get)
881 push_unique_key( L, CANCEL_ERROR); 900 push_unique_key( L, CANCEL_ERROR);
882 pushed = 1; 901 pushed = 1;
883 } 902 }
884 keeper_release( K); 903 // an error can be raised if we attempt to read an unregistered function
885 // must trigger error after keeper state has been released
886 // (an error can be raised if we attempt to read an unregistered function)
887 if( pushed < 0) 904 if( pushed < 0)
888 { 905 {
889 return luaL_error( L, "tried to copy unsupported types"); 906 return luaL_error( L, "tried to copy unsupported types");
@@ -913,8 +930,7 @@ LUAG_FUNC( linda_limit)
913 check_key_types( L, 2, 2); 930 check_key_types( L, 2, 2);
914 931
915 { 932 {
916 Keeper* K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); 933 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
917 if( K == NULL) return 0;
918 934
919 if( linda->simulate_cancel == CANCEL_NONE) 935 if( linda->simulate_cancel == CANCEL_NONE)
920 { 936 {
@@ -932,7 +948,6 @@ LUAG_FUNC( linda_limit)
932 push_unique_key( L, CANCEL_ERROR); 948 push_unique_key( L, CANCEL_ERROR);
933 pushed = 1; 949 pushed = 1;
934 } 950 }
935 keeper_release( K);
936 } 951 }
937 // propagate pushed boolean if any 952 // propagate pushed boolean if any
938 return pushed; 953 return pushed;
@@ -948,15 +963,11 @@ LUAG_FUNC( linda_cancel)
948{ 963{
949 struct s_Linda* linda = lua_toLinda( L, 1); 964 struct s_Linda* linda = lua_toLinda( L, 1);
950 char const* who = luaL_optstring( L, 2, "both"); 965 char const* who = luaL_optstring( L, 2, "both");
951 Keeper* K; 966 Keeper* K = which_keeper( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
952 967
953 // make sure we got 3 arguments: the linda, a key and a limit 968 // make sure we got 3 arguments: the linda, a key and a limit
954 luaL_argcheck( L, lua_gettop( L) <= 2, 2, "wrong number of arguments"); 969 luaL_argcheck( L, lua_gettop( L) <= 2, 2, "wrong number of arguments");
955 970
956 // signalling must be done from inside the K locking area
957 K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
958 if( K == NULL) return 0;
959
960 linda->simulate_cancel = CANCEL_SOFT; 971 linda->simulate_cancel = CANCEL_SOFT;
961 if( strcmp( who, "both") == 0) // tell everyone writers to wake up 972 if( strcmp( who, "both") == 0) // tell everyone writers to wake up
962 { 973 {
@@ -977,14 +988,6 @@ LUAG_FUNC( linda_cancel)
977 } 988 }
978 else 989 else
979 { 990 {
980 // error ...
981 linda = NULL;
982 }
983 keeper_release( K);
984
985 // ... but we must raise it outside the lock
986 if( !linda)
987 {
988 return luaL_error( L, "unknown wake hint '%s'", who); 991 return luaL_error( L, "unknown wake hint '%s'", who);
989 } 992 }
990 return 0; 993 return 0;
@@ -1184,18 +1187,16 @@ static void* linda_id( lua_State* L, DeepOp op_)
1184 struct s_Linda* linda = lua_touserdata( L, 1); 1187 struct s_Linda* linda = lua_touserdata( L, 1);
1185 ASSERT_L( linda); 1188 ASSERT_L( linda);
1186 1189
1187 /* Clean associated structures in the keeper state. 1190 // Clean associated structures in the keeper state.
1188 */
1189 K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda)); 1191 K = keeper_acquire( linda->U->keepers, LINDA_KEEPER_HASHSEED( linda));
1190 if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup) 1192 if( K && K->L) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup)
1191 { 1193 {
1194 // hopefully this won't ever raise an error as we would jump to the closest pcall site while forgetting to release the keeper mutex...
1192 keeper_call( linda->U, K->L, KEEPER_API( clear), L, linda, 0); 1195 keeper_call( linda->U, K->L, KEEPER_API( clear), L, linda, 0);
1193 } 1196 }
1194 keeper_release( K); 1197 keeper_release( K);
1195 1198
1196 /* There aren't any lanes waiting on these lindas, since all proxies 1199 // There aren't any lanes waiting on these lindas, since all proxies have been gc'ed. Right?
1197 * have been gc'ed. Right?
1198 */
1199 SIGNAL_FREE( &linda->read_happened); 1200 SIGNAL_FREE( &linda->read_happened);
1200 SIGNAL_FREE( &linda->write_happened); 1201 SIGNAL_FREE( &linda->write_happened);
1201 free( linda); 1202 free( linda);
@@ -1225,34 +1226,46 @@ static void* linda_id( lua_State* L, DeepOp op_)
1225 lua_pushcfunction( L, LG_linda_concat); 1226 lua_pushcfunction( L, LG_linda_concat);
1226 lua_setfield( L, -2, "__concat"); 1227 lua_setfield( L, -2, "__concat");
1227 1228
1228 // [-1]: linda metatable 1229 // protected calls, to ensure associated keeper is always released even in case of error
1230 // all function are the protected call wrapper, where the actual operation is provided as upvalue
1231 // note that this kind of thing can break function lookup as we use the function pointer here and there
1232
1229 lua_pushcfunction( L, LG_linda_send); 1233 lua_pushcfunction( L, LG_linda_send);
1234 lua_pushcclosure( L, LG_linda_protected_call, 1);
1230 lua_setfield( L, -2, "send"); 1235 lua_setfield( L, -2, "send");
1231 1236
1232 lua_pushcfunction( L, LG_linda_receive); 1237 lua_pushcfunction( L, LG_linda_receive);
1238 lua_pushcclosure( L, LG_linda_protected_call, 1);
1233 lua_setfield( L, -2, "receive"); 1239 lua_setfield( L, -2, "receive");
1234 1240
1235 lua_pushcfunction( L, LG_linda_limit); 1241 lua_pushcfunction( L, LG_linda_limit);
1242 lua_pushcclosure( L, LG_linda_protected_call, 1);
1236 lua_setfield( L, -2, "limit"); 1243 lua_setfield( L, -2, "limit");
1237 1244
1238 lua_pushcfunction( L, LG_linda_set); 1245 lua_pushcfunction( L, LG_linda_set);
1246 lua_pushcclosure( L, LG_linda_protected_call, 1);
1239 lua_setfield( L, -2, "set"); 1247 lua_setfield( L, -2, "set");
1240 1248
1241 lua_pushcfunction( L, LG_linda_count); 1249 lua_pushcfunction( L, LG_linda_count);
1250 lua_pushcclosure( L, LG_linda_protected_call, 1);
1242 lua_setfield( L, -2, "count"); 1251 lua_setfield( L, -2, "count");
1243 1252
1244 lua_pushcfunction( L, LG_linda_get); 1253 lua_pushcfunction( L, LG_linda_get);
1254 lua_pushcclosure( L, LG_linda_protected_call, 1);
1245 lua_setfield( L, -2, "get"); 1255 lua_setfield( L, -2, "get");
1246 1256
1247 lua_pushcfunction( L, LG_linda_cancel); 1257 lua_pushcfunction( L, LG_linda_cancel);
1258 lua_pushcclosure( L, LG_linda_protected_call, 1);
1248 lua_setfield( L, -2, "cancel"); 1259 lua_setfield( L, -2, "cancel");
1249 1260
1250 lua_pushcfunction( L, LG_linda_deep); 1261 lua_pushcfunction( L, LG_linda_deep);
1251 lua_setfield( L, -2, "deep"); 1262 lua_setfield( L, -2, "deep");
1252 1263
1253 lua_pushcfunction( L, LG_linda_dump); 1264 lua_pushcfunction( L, LG_linda_dump);
1265 lua_pushcclosure( L, LG_linda_protected_call, 1);
1254 lua_setfield( L, -2, "dump"); 1266 lua_setfield( L, -2, "dump");
1255 1267
1268 // some constants
1256 lua_pushliteral( L, BATCH_SENTINEL); 1269 lua_pushliteral( L, BATCH_SENTINEL);
1257 lua_setfield(L, -2, "batched"); 1270 lua_setfield(L, -2, "batched");
1258 1271
@@ -2074,13 +2087,14 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void* vs)
2074 // But don't register it in the lookup database because of the s_lane pointer upvalue 2087 // But don't register it in the lookup database because of the s_lane pointer upvalue
2075 lua_pushlightuserdata( L, s); 2088 lua_pushlightuserdata( L, s);
2076 lua_pushcclosure( L, LG_set_debug_threadname, 1); 2089 lua_pushcclosure( L, LG_set_debug_threadname, 1);
2077 lua_setglobal( L, "set_debug_threadname" ); 2090 lua_setglobal( L, "set_debug_threadname");
2078 2091
2079 // Tie "cancel_test()" to the state 2092 // Tie "cancel_test()" to the state
2080 lua_pushcfunction( L, LG_cancel_test); 2093 lua_pushcfunction( L, LG_cancel_test);
2081 populate_func_lookup_table( L, -1, "cancel_test"); 2094 populate_func_lookup_table( L, -1, "cancel_test");
2082 lua_setglobal( L, "cancel_test"); 2095 lua_setglobal( L, "cancel_test");
2083 2096
2097 // this could be done in lane_new before the lane body function is pushed on the stack to avoid unnecessary stack slot shifting around
2084#if ERROR_FULL_STACK 2098#if ERROR_FULL_STACK
2085 // Tie "set_error_reporting()" to the state 2099 // Tie "set_error_reporting()" to the state
2086 lua_pushcfunction( L, LG_set_error_reporting); 2100 lua_pushcfunction( L, LG_set_error_reporting);
@@ -2654,7 +2668,10 @@ LUAG_FUNC( thread_join)
2654 bool_t done = THREAD_ISNULL( s->thread) || THREAD_WAIT( &s->thread, wait_secs, &s->done_signal, &s->done_lock, &s->status); 2668 bool_t done = THREAD_ISNULL( s->thread) || THREAD_WAIT( &s->thread, wait_secs, &s->done_signal, &s->done_lock, &s->status);
2655 if( !done || !L2) 2669 if( !done || !L2)
2656 { 2670 {
2657 return 0; // timeout: pushes none, leaves 'L2' alive 2671 STACK_GROW( L, 2);
2672 lua_pushnil( L);
2673 lua_pushliteral( L, "timeout");
2674 return 2;
2658 } 2675 }
2659 2676
2660 STACK_CHECK( L); 2677 STACK_CHECK( L);
diff --git a/tests/deadlock.lua b/tests/deadlock.lua
new file mode 100644
index 0000000..8ccae89
--- /dev/null
+++ b/tests/deadlock.lua
@@ -0,0 +1,28 @@
1local lanes = require('lanes').configure()
2local linda = lanes.linda "deadlock_linda"
3
4local do_extra_stuff = true
5
6if do_extra_stuff then
7 -- just something to make send() succeed and receive() fail:
8 local payload = { lanes.require('socket').connect }
9
10 -- lane generator
11 local g = lanes.gen('*', function()
12 set_debug_threadname "deadlock_lane"
13 print("In lane 1:", table.unpack{pcall(linda.receive, linda, 'tmp')})
14 print("In lane 2:", table.unpack{pcall(linda.receive, linda, 'tmp')})
15 return 33, 55
16 end)
17
18 -- send payload twice
19 linda:send('tmp', payload, payload)
20 local h = g()
21 local err, stack = h:join()
22 print('we reach here and then deadlock', err, stack)
23end
24-- start lane
25
26-- wait some
27lanes.sleep(2)
28print('we never reach here') \ No newline at end of file