aboutsummaryrefslogtreecommitdiff
path: root/src/tools.c
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2011-02-12 17:06:03 +0100
committerBenoit Germain <bnt.germain@gmail.com>2011-02-12 17:06:03 +0100
commita661736f7984292a41d71847de68590f6b8ca08a (patch)
tree43e0799c20e835f1cc2d8c5fa1324b64301763e0 /src/tools.c
parentc91a03bd956bf19848253bded8217687ccd2ad81 (diff)
downloadlanes-a661736f7984292a41d71847de68590f6b8ca08a.tar.gz
lanes-a661736f7984292a41d71847de68590f6b8ca08a.tar.bz2
lanes-a661736f7984292a41d71847de68590f6b8ca08a.zip
Changed idfunc signature and contract to clarify that fact it is not lua-callable and to be able to require the module it was exported from in the target lanes.
Diffstat (limited to 'src/tools.c')
-rw-r--r--src/tools.c170
1 files changed, 100 insertions, 70 deletions
diff --git a/src/tools.c b/src/tools.c
index 6692890..d09b11e 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -280,26 +280,27 @@ void get_deep_lookup( lua_State *L ) {
280* or NULL if 'index' is not a deep userdata proxy. 280* or NULL if 'index' is not a deep userdata proxy.
281*/ 281*/
282static 282static
283lua_CFunction get_idfunc( lua_State *L, int index ) { 283luaG_IdFunction get_idfunc( lua_State *L, int index )
284 lua_CFunction ret; 284{
285 luaG_IdFunction ret;
285 286
286 index= STACK_ABS(L,index); 287 index= STACK_ABS(L,index);
287 288
288 STACK_GROW(L,1); 289 STACK_GROW(L,1);
289 290
290 STACK_CHECK(L) 291 STACK_CHECK(L)
291 if (!lua_getmetatable( L, index )) 292 if (!lua_getmetatable( L, index ))
292 return NULL; // no metatable 293 return NULL; // no metatable
293 294
294 // [-1]: metatable of [index] 295 // [-1]: metatable of [index]
295 296
296 get_deep_lookup(L); 297 get_deep_lookup(L);
297 // 298 //
298 // [-1]: idfunc/nil 299 // [-1]: idfunc/nil
299 300
300 ret= lua_tocfunction(L,-1); 301 ret= (luaG_IdFunction)lua_touserdata(L,-1);
301 lua_pop(L,1); 302 lua_pop(L,1);
302 STACK_END(L,0) 303 STACK_END(L,0)
303 return ret; 304 return ret;
304} 305}
305 306
@@ -311,7 +312,8 @@ lua_CFunction get_idfunc( lua_State *L, int index ) {
311* it up if reaches 0. 312* it up if reaches 0.
312*/ 313*/
313static 314static
314int deep_userdata_gc( lua_State *L ) { 315int deep_userdata_gc( lua_State *L )
316{
315 DEEP_PRELUDE **proxy= (DEEP_PRELUDE**)lua_touserdata( L, 1 ); 317 DEEP_PRELUDE **proxy= (DEEP_PRELUDE**)lua_touserdata( L, 1 );
316 DEEP_PRELUDE *p= *proxy; 318 DEEP_PRELUDE *p= *proxy;
317 int v; 319 int v;
@@ -319,27 +321,26 @@ int deep_userdata_gc( lua_State *L ) {
319 *proxy= 0; // make sure we don't use it any more 321 *proxy= 0; // make sure we don't use it any more
320 322
321 MUTEX_LOCK( &deep_lock ); 323 MUTEX_LOCK( &deep_lock );
322 v= --(p->refcount); 324 v= --(p->refcount);
323 MUTEX_UNLOCK( &deep_lock ); 325 MUTEX_UNLOCK( &deep_lock );
324 326
325 if (v==0) { 327 if (v==0)
326 int pushed; 328 {
327
328 // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup 329 // Call 'idfunc( "delete", deep_ptr )' to make deep cleanup
329 // 330 //
330 lua_CFunction idfunc= get_idfunc(L,1); 331 luaG_IdFunction idfunc = get_idfunc(L,1);
331 ASSERT_L(idfunc); 332 ASSERT_L(idfunc);
332 333
333 lua_settop(L,0); // clean stack so we can call 'idfunc' directly 334 lua_settop( L, 0); // clean stack so we can call 'idfunc' directly
334 335
335 // void= idfunc( "delete", lightuserdata ) 336 // void= idfunc( "delete", lightuserdata )
336 // 337 //
337 lua_pushliteral( L, "delete" );
338 lua_pushlightuserdata( L, p->deep ); 338 lua_pushlightuserdata( L, p->deep );
339 pushed= idfunc(L); 339 idfunc( L, "delete");
340 340
341 if (pushed) 341 // top was set to 0, then userdata was pushed. "delete" might want to pop the userdata (we don't care), but should not push anything!
342 luaL_error( L, "Bad idfunc on \"delete\": returned something" ); 342 if ( lua_gettop( L) > 1)
343 luaL_error( L, "Bad idfunc on \"delete\": returned something");
343 344
344 DEEP_FREE( (void*)p ); 345 DEEP_FREE( (void*)p );
345 } 346 }
@@ -354,28 +355,31 @@ int deep_userdata_gc( lua_State *L ) {
354* used in this Lua state (metatable, registring it). Otherwise, increments the 355* used in this Lua state (metatable, registring it). Otherwise, increments the
355* reference count. 356* reference count.
356*/ 357*/
357void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude ) { 358void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *prelude )
359{
358 DEEP_PRELUDE **proxy; 360 DEEP_PRELUDE **proxy;
359 361
360 // Check if a proxy already exists 362 // Check if a proxy already exists
361 push_registry_subtable_mode(L, DEEP_PROXY_CACHE_KEY, "v"); 363 push_registry_subtable_mode(L, DEEP_PROXY_CACHE_KEY, "v");
362 lua_pushlightuserdata(L, prelude->deep); 364 lua_pushlightuserdata(L, prelude->deep);
363 lua_rawget(L, -2); 365 lua_rawget(L, -2);
364 if (!lua_isnil(L, -1)) { 366 if (!lua_isnil(L, -1))
367 {
365 lua_remove(L, -2); // deep proxy cache table 368 lua_remove(L, -2); // deep proxy cache table
366 return; 369 return;
367 } else { 370 }
371 else
372 {
368 lua_pop(L, 2); // Pop the nil and proxy cache table 373 lua_pop(L, 2); // Pop the nil and proxy cache table
369 } 374 }
370 375
371
372 MUTEX_LOCK( &deep_lock ); 376 MUTEX_LOCK( &deep_lock );
373 ++(prelude->refcount); // one more proxy pointing to this deep data 377 ++(prelude->refcount); // one more proxy pointing to this deep data
374 MUTEX_UNLOCK( &deep_lock ); 378 MUTEX_UNLOCK( &deep_lock );
375 379
376 STACK_GROW(L,4); 380 STACK_GROW(L,4);
377 381
378 STACK_CHECK(L) 382 STACK_CHECK(L)
379 383
380 proxy= lua_newuserdata( L, sizeof( DEEP_PRELUDE* ) ); 384 proxy= lua_newuserdata( L, sizeof( DEEP_PRELUDE* ) );
381 ASSERT_L(proxy); 385 ASSERT_L(proxy);
@@ -383,28 +387,32 @@ void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude
383 387
384 // Get/create metatable for 'idfunc' (in this state) 388 // Get/create metatable for 'idfunc' (in this state)
385 // 389 //
386 lua_pushcfunction( L, idfunc ); // key 390 lua_pushlightuserdata( L, idfunc ); // key
387 get_deep_lookup(L); 391 get_deep_lookup(L);
388 // 392 //
389 // [-2]: proxy 393 // [-2]: proxy
390 // [-1]: metatable / nil 394 // [-1]: metatable / nil
391 395
392 if (lua_isnil(L,-1)) { 396 if (lua_isnil(L,-1))
393 // No metatable yet; make one and register it 397 {
394 // 398 int oldtop;
399 // No metatable yet. We have two things to do:
400
401 // 1 - make one and register it
395 lua_pop(L,1); 402 lua_pop(L,1);
396 403
397 // tbl= idfunc( "metatable" ) 404 // tbl= idfunc( "metatable" )
398 // 405 //
399 lua_pushcfunction( L, idfunc ); 406 oldtop = lua_gettop( L);
400 lua_pushliteral( L, "metatable" ); 407 idfunc( L, "metatable");
401 lua_call( L, 1 /*args*/, 1 /*results*/ ); 408 //
402 // 409 // [-2]: proxy
403 // [-2]: proxy 410 // [-1]: metatable (returned by 'idfunc')
404 // [-1]: metatable (returned by 'idfunc')
405 411
406 if (!lua_istable(L,-1)) 412 if (lua_gettop( L) - oldtop != 1 || !lua_istable(L, -1))
413 {
407 luaL_error( L, "Bad idfunc on \"metatable\": did not return one" ); 414 luaL_error( L, "Bad idfunc on \"metatable\": did not return one" );
415 }
408 416
409 // Add '__gc' method 417 // Add '__gc' method
410 // 418 //
@@ -414,16 +422,40 @@ void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude
414 // Memorize for later rounds 422 // Memorize for later rounds
415 // 423 //
416 lua_pushvalue( L,-1 ); 424 lua_pushvalue( L,-1 );
417 lua_pushcfunction( L, idfunc ); 425 lua_pushlightuserdata( L, idfunc );
418 // 426 //
419 // [-4]: proxy 427 // [-4]: proxy
420 // [-3]: metatable (2nd ref) 428 // [-3]: metatable (2nd ref)
421 // [-2]: metatable 429 // [-2]: metatable
422 // [-1]: idfunc 430 // [-1]: idfunc
423 431
424 set_deep_lookup(L); 432 set_deep_lookup(L);
425 } 433
426 STACK_MID(L,2) 434 // 2 - cause the target state to require the module that exported the idfunc
435 // this is needed because we must make sure the shared library is still loaded as long as we hold a pointer on the idfunc
436 lua_getglobal( L, "require");
437 if( lua_isfunction( L, -1)) // just in case...
438 {
439 // make sure the function pushed a single value on the stack!
440 int oldtop = lua_gettop( L);
441 idfunc( L, "module");
442 if( lua_gettop( L) - oldtop != 1 || !lua_isstring( L, -1))
443 {
444 luaL_error( L, "Bad idfunc on \"module\": should return a string");
445 }
446 // if we are inside a call to require, this will raise a "reentrency" error that we absorb silently (we don't care, this probably means the module is already being required, which is what we need)
447 if( lua_pcall( L, 1, 0, 0) != 0)
448 {
449 //char const * const errMsg = lua_tostring( L, -1); // just to see it in the debugger
450 lua_pop( L, 1);
451 }
452 }
453 else
454 {
455 lua_pop( L, 1);
456 }
457 }
458 STACK_MID(L,2)
427 ASSERT_L( lua_isuserdata(L,-2) ); 459 ASSERT_L( lua_isuserdata(L,-2) );
428 ASSERT_L( lua_istable(L,-1) ); 460 ASSERT_L( lua_istable(L,-1) );
429 461
@@ -439,7 +471,7 @@ void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude
439 lua_rawset(L, -3); 471 lua_rawset(L, -3);
440 lua_pop(L, 1); // Remove the cache proxy table 472 lua_pop(L, 1); // Remove the cache proxy table
441 473
442 STACK_END(L,1) 474 STACK_END(L,1)
443 // [-1]: proxy userdata 475 // [-1]: proxy userdata
444} 476}
445 477
@@ -466,9 +498,9 @@ void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude
466* 498*
467* Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()' 499* Returns: 'proxy' userdata for accessing the deep data via 'luaG_todeep()'
468*/ 500*/
469int luaG_deep_userdata( lua_State *L ) { 501int luaG_deep_userdata( lua_State *L, luaG_IdFunction idfunc)
470 lua_CFunction idfunc= lua_tocfunction( L,1 ); 502{
471 int pushed; 503 int oldtop;
472 504
473 DEEP_PRELUDE *prelude= DEEP_MALLOC( sizeof(DEEP_PRELUDE) ); 505 DEEP_PRELUDE *prelude= DEEP_MALLOC( sizeof(DEEP_PRELUDE) );
474 ASSERT_L(prelude); 506 ASSERT_L(prelude);
@@ -476,20 +508,17 @@ int luaG_deep_userdata( lua_State *L ) {
476 prelude->refcount= 0; // 'luaG_push_proxy' will lift it to 1 508 prelude->refcount= 0; // 'luaG_push_proxy' will lift it to 1
477 509
478 STACK_GROW(L,1); 510 STACK_GROW(L,1);
479 STACK_CHECK(L) 511 STACK_CHECK(L)
480
481 // Replace 'idfunc' with "new" in the stack (keep possible other params)
482 //
483 lua_remove(L,1);
484 lua_pushliteral( L, "new" );
485 lua_insert(L,1);
486 512
487 // lightuserdata= idfunc( "new" [, ...] ) 513 // lightuserdata= idfunc( "new" [, ...] )
488 // 514 //
489 pushed= idfunc(L); 515 oldtop = lua_gettop( L);
516 idfunc(L, "new");
490 517
491 if ((pushed!=1) || lua_type(L,-1) != LUA_TLIGHTUSERDATA) 518 if( lua_gettop( L) - oldtop != 1 || lua_type( L, -1) != LUA_TLIGHTUSERDATA)
492 luaL_error( L, "Bad idfunc on \"new\": did not return light userdata" ); 519 {
520 luaL_error( L, "Bad idfunc on \"new\": did not return light userdata");
521 }
493 522
494 prelude->deep= lua_touserdata(L,-1); 523 prelude->deep= lua_touserdata(L,-1);
495 ASSERT_L(prelude->deep); 524 ASSERT_L(prelude->deep);
@@ -497,10 +526,10 @@ int luaG_deep_userdata( lua_State *L ) {
497 lua_pop(L,1); // pop deep data 526 lua_pop(L,1); // pop deep data
498 527
499 luaG_push_proxy( L, idfunc, prelude ); 528 luaG_push_proxy( L, idfunc, prelude );
500 // 529 //
501 // [-1]: proxy userdata 530 // [-1]: proxy userdata
502 531
503 STACK_END(L,1) 532 STACK_END(L,1)
504 return 1; 533 return 1;
505} 534}
506 535
@@ -511,15 +540,16 @@ int luaG_deep_userdata( lua_State *L ) {
511* Reference count is not changed, and access to the deep userdata is not 540* Reference count is not changed, and access to the deep userdata is not
512* serialized. It is the module's responsibility to prevent conflicting usage. 541* serialized. It is the module's responsibility to prevent conflicting usage.
513*/ 542*/
514void *luaG_todeep( lua_State *L, lua_CFunction idfunc, int index ) { 543void *luaG_todeep( lua_State *L, luaG_IdFunction idfunc, int index )
544{
515 DEEP_PRELUDE **proxy; 545 DEEP_PRELUDE **proxy;
516 546
517 STACK_CHECK(L) 547 STACK_CHECK(L)
518 if (get_idfunc(L,index) != idfunc) 548 if( get_idfunc(L,index) != idfunc)
519 return NULL; // no metatable, or wrong kind 549 return NULL; // no metatable, or wrong kind
520 550
521 proxy= (DEEP_PRELUDE**)lua_touserdata( L, index ); 551 proxy= (DEEP_PRELUDE**)lua_touserdata( L, index );
522 STACK_END(L,0) 552 STACK_END(L,0)
523 553
524 return (*proxy)->deep; 554 return (*proxy)->deep;
525} 555}
@@ -533,14 +563,14 @@ void *luaG_todeep( lua_State *L, lua_CFunction idfunc, int index ) {
533* (not copied) 563* (not copied)
534*/ 564*/
535static 565static
536lua_CFunction luaG_copydeep( lua_State *L, lua_State *L2, int index ) { 566luaG_IdFunction luaG_copydeep( lua_State *L, lua_State *L2, int index )
567{
537 DEEP_PRELUDE **proxy; 568 DEEP_PRELUDE **proxy;
538 DEEP_PRELUDE *p; 569 DEEP_PRELUDE *p;
539 570
540 lua_CFunction idfunc; 571 luaG_IdFunction idfunc = get_idfunc( L, index);
541 572 if (!idfunc)
542 idfunc= get_idfunc( L, index ); 573 return NULL; // not a deep userdata
543 if (!idfunc) return NULL; // not a deep userdata
544 574
545 // Increment reference count 575 // Increment reference count
546 // 576 //