diff options
author | Benoit Germain <bnt.germain@gmail.com> | 2011-02-12 17:06:03 +0100 |
---|---|---|
committer | Benoit Germain <bnt.germain@gmail.com> | 2011-02-12 17:06:03 +0100 |
commit | a661736f7984292a41d71847de68590f6b8ca08a (patch) | |
tree | 43e0799c20e835f1cc2d8c5fa1324b64301763e0 /src/tools.c | |
parent | c91a03bd956bf19848253bded8217687ccd2ad81 (diff) | |
download | lanes-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.c | 170 |
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 | */ |
282 | static | 282 | static |
283 | lua_CFunction get_idfunc( lua_State *L, int index ) { | 283 | luaG_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 | */ |
313 | static | 314 | static |
314 | int deep_userdata_gc( lua_State *L ) { | 315 | int 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 | */ |
357 | void luaG_push_proxy( lua_State *L, lua_CFunction idfunc, DEEP_PRELUDE *prelude ) { | 358 | void 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 | */ |
469 | int luaG_deep_userdata( lua_State *L ) { | 501 | int 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 | */ |
514 | void *luaG_todeep( lua_State *L, lua_CFunction idfunc, int index ) { | 543 | void *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 | */ |
535 | static | 565 | static |
536 | lua_CFunction luaG_copydeep( lua_State *L, lua_State *L2, int index ) { | 566 | luaG_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 | // |