aboutsummaryrefslogtreecommitdiff
path: root/src/lanes.c
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2011-04-18 08:25:23 +0200
committerBenoit Germain <bnt.germain@gmail.com>2011-04-18 08:25:23 +0200
commit05256f1e75f8583829bbaa7cdf1fb1518b93332a (patch)
treefc0d9a6855b6c05e06b06c933be8726bf546659c /src/lanes.c
parent2d5d798c24286f10c1bffd5ea4ac466c2c3a12fa (diff)
downloadlanes-05256f1e75f8583829bbaa7cdf1fb1518b93332a.tar.gz
lanes-05256f1e75f8583829bbaa7cdf1fb1518b93332a.tar.bz2
lanes-05256f1e75f8583829bbaa7cdf1fb1518b93332a.zip
* linda uses a fast FIFO implementation to speed up data exchanges
* new linda:count() method * new linda batched data read mode * proper key type check in all linda methods * fix setup-vc.cmd to support Visual Studio 2010 and Windows 7 64 bits * bugfix: release keeper state mutex at desinit
Diffstat (limited to 'src/lanes.c')
-rw-r--r--src/lanes.c159
1 files changed, 106 insertions, 53 deletions
diff --git a/src/lanes.c b/src/lanes.c
index e06d367..e514e6b 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -51,7 +51,7 @@
51 * ... 51 * ...
52 */ 52 */
53 53
54const char *VERSION= "2.1.0"; 54const char *VERSION= "2.2.0";
55 55
56/* 56/*
57=============================================================================== 57===============================================================================
@@ -249,6 +249,20 @@ static void linda_id( lua_State*, char const * const which);
249#define lua_toLinda(L,n) ((struct s_Linda *)luaG_todeep( L, linda_id, n )) 249#define lua_toLinda(L,n) ((struct s_Linda *)luaG_todeep( L, linda_id, n ))
250 250
251 251
252static void check_key_types( lua_State *L, int _start, int _end)
253{
254 int i;
255 for( i = _start; i <= _end; ++ i)
256 {
257 int t = lua_type( L, i);
258 if( t == LUA_TBOOLEAN || t == LUA_TNUMBER || t == LUA_TSTRING || t == LUA_TLIGHTUSERDATA)
259 {
260 continue;
261 }
262 luaL_error( L, "argument #%d: invalid key type (not a boolean, string, number or light userdata)", i);
263 }
264}
265
252/* 266/*
253* bool= linda_send( linda_ud, [timeout_secs=-1,] key_num|str|bool|lightuserdata, ... ) 267* bool= linda_send( linda_ud, [timeout_secs=-1,] key_num|str|bool|lightuserdata, ... )
254* 268*
@@ -271,15 +285,18 @@ LUAG_FUNC( linda_send)
271 if( lua_isnumber(L, 2)) 285 if( lua_isnumber(L, 2))
272 { 286 {
273 timeout= SIGNAL_TIMEOUT_PREPARE( lua_tonumber(L,2) ); 287 timeout= SIGNAL_TIMEOUT_PREPARE( lua_tonumber(L,2) );
274 key_i++; 288 ++ key_i;
275 } 289 }
276 else if( lua_isnil( L, 2)) 290 else if( lua_isnil( L, 2)) // alternate explicit "no timeout" by passing nil before the key
277 { 291 {
278 key_i++; 292 ++ key_i;
279 } 293 }
280 294
281 if( lua_isnil( L, key_i)) 295 // make sure the keys are of a valid type
282 luaL_error( L, "nil key" ); 296 check_key_types( L, key_i, key_i);
297
298 // convert nils to some special non-nil sentinel in sent values
299 keeper_toggle_nil_sentinels( L, key_i + 1, 1);
283 300
284 STACK_GROW(L, 1); 301 STACK_GROW(L, 1);
285 { 302 {
@@ -315,11 +332,11 @@ LUAG_FUNC( linda_send)
315 332
316 cancel = cancel_test( L); // testing here causes no delays 333 cancel = cancel_test( L); // testing here causes no delays
317 if (cancel) 334 if (cancel)
335 {
318 break; 336 break;
337 }
319 338
320 // Bugfix by Benoit Germain Dec-2009: change status of lane to "waiting" 339 // change status of lane to "waiting"
321 //
322#if 1
323 { 340 {
324 struct s_lane *s; 341 struct s_lane *s;
325 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings 342 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings
@@ -338,6 +355,7 @@ LUAG_FUNC( linda_send)
338 ASSERT_L( s->waiting_on == NULL); 355 ASSERT_L( s->waiting_on == NULL);
339 s->waiting_on = &linda->read_happened; 356 s->waiting_on = &linda->read_happened;
340 } 357 }
358 // could not send because no room: wait until some data was read before trying again, or until timeout is reached
341 if( !SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout)) 359 if( !SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout))
342 { 360 {
343 if( s) 361 if( s)
@@ -353,12 +371,6 @@ LUAG_FUNC( linda_send)
353 s->status = prev_status; 371 s->status = prev_status;
354 } 372 }
355 } 373 }
356#else
357 // K lock will be released for the duration of wait and re-acquired
358 //
359 if( !SIGNAL_WAIT( &linda->read_happened, &K->lock_, timeout))
360 break; // timeout
361#endif
362 } 374 }
363 STACK_END( KL, 0) 375 STACK_END( KL, 0)
364 keeper_release( K); 376 keeper_release( K);
@@ -379,18 +391,23 @@ LUAG_FUNC( linda_send)
379 391
380 392
381/* 393/*
382* [val, key]= linda_receive( linda_ud, [timeout_secs_num=-1], key_num|str|bool|lightuserdata [, ...] ) 394 * 2 modes of operation
383* 395 * [val, key]= linda_receive( linda_ud, [timeout_secs_num=-1], key_num|str|bool|lightuserdata [, ...] )
384* Receive a value from Linda, consuming it. 396 * Consumes a single value from the Linda, in any key.
385* 397 * Returns: received value (which is consumed from the slot), and the key which had it
386* Returns: value received (which is consumed from the slot) 398
387* key which had it 399 * [val1, ... valCOUNT]= linda_receive( linda_ud, [timeout_secs_num=-1], linda.batched, key_num|str|bool|lightuserdata, COUNT)
388*/ 400 * Consumes COUNT values from the linda, from a single key.
401 * returns the COUNT consumed values, or nil if there weren't enough values to consume
402 *
403 */
404#define BATCH_SENTINEL "270e6c9d-280f-4983-8fee-a7ecdda01475"
389LUAG_FUNC( linda_receive) 405LUAG_FUNC( linda_receive)
390{ 406{
391 struct s_Linda *linda = lua_toLinda( L, 1); 407 struct s_Linda *linda = lua_toLinda( L, 1);
392 int pushed; 408 int pushed, expected_pushed;
393 bool_t cancel = FALSE; 409 bool_t cancel = FALSE;
410 char *keeper_receive;
394 411
395 time_d timeout = -1.0; 412 time_d timeout = -1.0;
396 uint_t key_i = 2; 413 uint_t key_i = 2;
@@ -400,26 +417,44 @@ LUAG_FUNC( linda_receive)
400 if( lua_isnumber( L, 2)) 417 if( lua_isnumber( L, 2))
401 { 418 {
402 timeout = SIGNAL_TIMEOUT_PREPARE( lua_tonumber( L, 2)); 419 timeout = SIGNAL_TIMEOUT_PREPARE( lua_tonumber( L, 2));
403 key_i++; 420 ++ key_i;
404 } 421 }
405 else if( lua_isnil( L, 2)) 422 else if( lua_isnil( L, 2)) // alternate explicit "no timeout" by passing nil before the key
406 { 423 {
407 key_i++; 424 ++ key_i;
408 } 425 }
409 426
427 // make sure the keys are of a valid type
428 check_key_types( L, key_i, lua_gettop( L));
429
430 // are we in batched mode?
431 lua_pushliteral( L, BATCH_SENTINEL);
432 if( lua_equal( L, key_i, -1))
433 {
434 keeper_receive = "receive_batched";
435 expected_pushed = (int)luaL_checkinteger( L, key_i + 2);
436 }
437 else
438 {
439 keeper_receive = "receive";
440 expected_pushed = 2;
441 }
442 lua_pop( L, 1);
443
410 { 444 {
411 struct s_Keeper *K = keeper_acquire( linda); 445 struct s_Keeper *K = keeper_acquire( linda);
412 for( ;;) 446 for( ;;)
413 { 447 {
414 pushed = keeper_call( K->L, "receive", L, linda, key_i); 448 pushed = keeper_call( K->L, keeper_receive, L, linda, key_i);
415 if( pushed < 0) 449 if( pushed < 0)
416 { 450 {
417 break; 451 break;
418 } 452 }
419 if( pushed > 0) 453 if( pushed > 0)
420 { 454 {
421 ASSERT_L( pushed == 2); 455 ASSERT_L( pushed == expected_pushed);
422 456 // replace sentinels with real nils
457 keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, 0);
423 // To be done from within the 'K' locking area 458 // To be done from within the 'K' locking area
424 // 459 //
425 SIGNAL_ALL( &linda->read_happened); 460 SIGNAL_ALL( &linda->read_happened);
@@ -438,9 +473,7 @@ LUAG_FUNC( linda_receive)
438 break; 473 break;
439 } 474 }
440 475
441 // Bugfix by Benoit Germain Dec-2009: change status of lane to "waiting" 476 // change status of lane to "waiting"
442 //
443#if 1
444 { 477 {
445 struct s_lane *s; 478 struct s_lane *s;
446 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings 479 enum e_status prev_status = ERROR_ST; // prevent 'might be used uninitialized' warnings
@@ -459,6 +492,7 @@ LUAG_FUNC( linda_receive)
459 ASSERT_L( s->waiting_on == NULL); 492 ASSERT_L( s->waiting_on == NULL);
460 s->waiting_on = &linda->write_happened; 493 s->waiting_on = &linda->write_happened;
461 } 494 }
495 // not enough data to read: wakeup when data was sent, or when timeout is reached
462 if( !SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout)) 496 if( !SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout))
463 { 497 {
464 if( s) 498 if( s)
@@ -474,12 +508,6 @@ LUAG_FUNC( linda_receive)
474 s->status = prev_status; 508 s->status = prev_status;
475 } 509 }
476 } 510 }
477#else
478 // Release the K lock for the duration of wait, and re-acquire
479 //
480 if( !SIGNAL_WAIT( &linda->write_happened, &K->lock_, timeout))
481 break;
482#endif
483 } 511 }
484 keeper_release( K); 512 keeper_release( K);
485 } 513 }
@@ -501,6 +529,7 @@ LUAG_FUNC( linda_receive)
501* = linda_set( linda_ud, key_num|str|bool|lightuserdata [,value] ) 529* = linda_set( linda_ud, key_num|str|bool|lightuserdata [,value] )
502* 530*
503* Set a value to Linda. 531* Set a value to Linda.
532* TODO: what do we do if we set to non-nil and limit is 0?
504* 533*
505* Existing slot value is replaced, and possible queue entries removed. 534* Existing slot value is replaced, and possible queue entries removed.
506*/ 535*/
@@ -510,9 +539,14 @@ LUAG_FUNC( linda_set)
510 bool_t has_value = !lua_isnil( L, 3); 539 bool_t has_value = !lua_isnil( L, 3);
511 luaL_argcheck( L, linda, 1, "expected a linda object!"); 540 luaL_argcheck( L, linda, 1, "expected a linda object!");
512 541
542 // make sure the key is of a valid type
543 check_key_types( L, 2, 2);
544
513 { 545 {
546 int pushed;
514 struct s_Keeper *K = keeper_acquire( linda); 547 struct s_Keeper *K = keeper_acquire( linda);
515 int pushed = keeper_call( K->L, "set", L, linda, 2); 548 // no nil->sentinel toggling, we really clear the linda contents for the given key with a set()
549 pushed = keeper_call( K->L, "set", L, linda, 2);
516 if( pushed >= 0) // no error? 550 if( pushed >= 0) // no error?
517 { 551 {
518 ASSERT_L( pushed == 0); 552 ASSERT_L( pushed == 0);
@@ -537,28 +571,28 @@ LUAG_FUNC( linda_set)
537 571
538 572
539/* 573/*
540* [val]= linda_keys( linda_ud) 574 * [val] = linda_count( linda_ud, [key [, ...]])
541* 575 *
542* Get the list of keys with pending data in the linda 576 * Get a count of the pending elements in the specified keys
543*/ 577 */
544LUAG_FUNC( linda_keys) 578LUAG_FUNC( linda_count)
545{ 579{
546 struct s_Linda *linda= lua_toLinda( L, 1); 580 struct s_Linda *linda= lua_toLinda( L, 1);
547 int pushed; 581 int pushed;
582
548 luaL_argcheck( L, linda, 1, "expected a linda object!"); 583 luaL_argcheck( L, linda, 1, "expected a linda object!");
584 // make sure the keys are of a valid type
585 check_key_types( L, 2, lua_gettop( L));
549 586
550 { 587 {
551 struct s_Keeper *K = keeper_acquire( linda); 588 struct s_Keeper *K = keeper_acquire( linda);
552 pushed = keeper_call( K->L, "keys", L, linda, 2); 589 pushed = keeper_call( K->L, "count", L, linda, 2);
553 ASSERT_L( pushed==0 || pushed==1 ); 590 keeper_release( K);
554 keeper_release(K);
555 // must trigger error after keeper state has been released
556 if( pushed < 0) 591 if( pushed < 0)
557 { 592 {
558 luaL_error( L, "tried to copy unsupported types"); 593 luaL_error( L, "tried to count an invalid key");
559 } 594 }
560 } 595 }
561
562 return pushed; 596 return pushed;
563} 597}
564 598
@@ -567,17 +601,25 @@ LUAG_FUNC( linda_keys)
567* [val]= linda_get( linda_ud, key_num|str|bool|lightuserdata ) 601* [val]= linda_get( linda_ud, key_num|str|bool|lightuserdata )
568* 602*
569* Get a value from Linda. 603* Get a value from Linda.
604* TODO: add support to get multiple values?
570*/ 605*/
571LUAG_FUNC( linda_get) 606LUAG_FUNC( linda_get)
572{ 607{
573 struct s_Linda *linda= lua_toLinda( L, 1); 608 struct s_Linda *linda= lua_toLinda( L, 1);
574 int pushed; 609 int pushed;
610
575 luaL_argcheck( L, linda, 1, "expected a linda object!"); 611 luaL_argcheck( L, linda, 1, "expected a linda object!");
612 // make sure the key is of a valid type
613 check_key_types( L, 2, 2);
576 614
577 { 615 {
578 struct s_Keeper *K = keeper_acquire( linda); 616 struct s_Keeper *K = keeper_acquire( linda);
579 pushed = keeper_call( K->L, "get", L, linda, 2); 617 pushed = keeper_call( K->L, "get", L, linda, 2);
580 ASSERT_L( pushed==0 || pushed==1 ); 618 ASSERT_L( pushed==0 || pushed==1 );
619 if( pushed > 0)
620 {
621 keeper_toggle_nil_sentinels( L, lua_gettop( L) - pushed, 0);
622 }
581 keeper_release(K); 623 keeper_release(K);
582 // must trigger error after keeper state has been released 624 // must trigger error after keeper state has been released
583 if( pushed < 0) 625 if( pushed < 0)
@@ -598,7 +640,10 @@ LUAG_FUNC( linda_get)
598LUAG_FUNC( linda_limit) 640LUAG_FUNC( linda_limit)
599{ 641{
600 struct s_Linda *linda= lua_toLinda( L, 1 ); 642 struct s_Linda *linda= lua_toLinda( L, 1 );
643
601 luaL_argcheck( L, linda, 1, "expected a linda object!"); 644 luaL_argcheck( L, linda, 1, "expected a linda object!");
645 // make sure the key is of a valid type
646 check_key_types( L, 2, 2);
602 647
603 { 648 {
604 struct s_Keeper *K = keeper_acquire( linda); 649 struct s_Keeper *K = keeper_acquire( linda);
@@ -775,21 +820,24 @@ static void linda_id( lua_State *L, char const * const which)
775 lua_pushcfunction( L, LG_linda_receive ); 820 lua_pushcfunction( L, LG_linda_receive );
776 lua_setfield( L, -2, "receive" ); 821 lua_setfield( L, -2, "receive" );
777 822
778 lua_pushcfunction( L, LG_linda_keys );
779 lua_setfield( L, -2, "keys" );
780
781 lua_pushcfunction( L, LG_linda_limit ); 823 lua_pushcfunction( L, LG_linda_limit );
782 lua_setfield( L, -2, "limit" ); 824 lua_setfield( L, -2, "limit" );
783 825
784 lua_pushcfunction( L, LG_linda_set ); 826 lua_pushcfunction( L, LG_linda_set );
785 lua_setfield( L, -2, "set" ); 827 lua_setfield( L, -2, "set" );
786 828
829 lua_pushcfunction( L, LG_linda_count );
830 lua_setfield( L, -2, "count" );
831
787 lua_pushcfunction( L, LG_linda_get ); 832 lua_pushcfunction( L, LG_linda_get );
788 lua_setfield( L, -2, "get" ); 833 lua_setfield( L, -2, "get" );
789 834
790 lua_pushcfunction( L, LG_linda_deep ); 835 lua_pushcfunction( L, LG_linda_deep );
791 lua_setfield( L, -2, "deep" ); 836 lua_setfield( L, -2, "deep" );
792 837
838 lua_pushliteral( L, BATCH_SENTINEL);
839 lua_setfield(L, -2, "batched");
840
793 STACK_END(L,1) 841 STACK_END(L,1)
794 } 842 }
795 else if( strcmp( which, "module") == 0) 843 else if( strcmp( which, "module") == 0)
@@ -803,6 +851,11 @@ static void linda_id( lua_State *L, char const * const which)
803 } 851 }
804} 852}
805 853
854/*
855 * ud = lanes.linda()
856 *
857 * returns a linda object
858 */
806LUAG_FUNC( linda) 859LUAG_FUNC( linda)
807{ 860{
808 return luaG_deep_userdata( L, linda_id); 861 return luaG_deep_userdata( L, linda_id);