views:

180

answers:

1

I'm working on a small project for the iPad and I simply want to run a script that will halt after certain function calls and then let me resume the script from the same place later on. In fact I only do 'threads' one at a time in a queue so it's really only multitasking between the iPhone OS and Lua.

static int yield__ (lua_State *L) {
//NSLog(@"Do Yield");
return lua_yield(L, 0);
}

//This function adds a script to my queue
- (void) doFileThreaded:(NSString*)filename {

NSString* path = [[NSBundle mainBundle] pathForResource:filename ofType:nil];
const char* file = [path UTF8String];

lua_State* newThread = lua_newthread(luaState);

//Load the file for execution
if ( luaL_loadfile(newThread,file) != 0 ) {
    return;
}   
//Add file to the queue
[threads addObject:[NSValue valueWithPointer:newThread]];
}

//This Function Executes the queued threads one at a time removing them when they've finished
- (void) doThreads {

lua_State* thread = NULL;

while ( threads.count > 0 ) {

    thread = (lua_State*)[[threads objectAtIndex:0] pointerValue];

    //Resume will run a thread until it yeilds execution
    switch ( lua_resume(thread, 0) ) {
        case LUA_YIELD:
            //NSLog(@"Recieved Yield");
            return;

        case 0:
            NSLog(@"Removing Thread");
            [threads removeObjectAtIndex:0];
            thread = NULL;
            break;
        default:
            NSLog(@"Error Executing Threaded Script!");
            [threads removeObjectAtIndex:0];
            break;

    }

}

}

Now For the Lua code:

function wait (seconds)

  time = os.time() + seconds;
  print("Waiting " .. os.time() .. " to " .. time);
  while ( time > os.time() ) do
    yield(); --I have written my own yield function
  end

end

print("Entered Toad Behavior");

yield();

print("Point 1");

yield();

print("point 3");

wait(1);

print("point 4");

wait(2);

print("point 5");

This code will crash on the second call to wait in lua. With a BAD_MEMORY_ACCESS or lua_resume sometimes returns a runtime error. (I don't know how to check what the error is, so if you could help me with that I'd appreciate that too) Can anyone out there tell me what I'm doing wrong here?

+3  A: 

Ok, I don't understand it 100% but I believe it has something to do with the fact that I was calling doFileThreaded from another executing lua script. It would seem that even though the lua_State is different the fact that I called luaL_loadfile from a function that was already being called by Lua that this was still somehow causing an "attempt to yield across metamethod/C-call boundary"

My solution was to save the names of the files I wanted to run as strings into an array, and then call lua_newthread in doThread.

- (void) doFileThreaded:(NSString*)filename {

NSString* path = [[NSBundle mainBundle] pathForResource:filename ofType:nil];

//Add to queue
[threads addObject:path];
}

- (void) doThreads {

//Will run through the threads in the order they've been queued.
//Cooperative Multitasking

while ( threads.count > 0 ) {

    //If there is no thread start one
    if ( threadState == NULL ) {

        threadState = lua_newthread(luaState);

        const char* file = [[threads objectAtIndex:0] UTF8String];

        if ( luaL_loadfile(threadState,file) != 0 ) {
            NSLog(@"%s\n", lua_tostring(threadState,-1));
            [threads removeObjectAtIndex:0];
            threadState = NULL;
            return;
        }

        //Return because we don't want to resume the file right away
        //return;

    }

    //Resume will run a thread until it yeilds execution
    switch ( lua_resume(threadState, 0) ) {
        case LUA_YIELD:
            return;

        case 0:
            //New Thread
            NSLog(@"Thread Returned");
            threadState = NULL;
            [threads removeObjectAtIndex:0];
            break;

        case LUA_ERRMEM:
            NSLog(@"LUA_ERRMEM");
            NSLog(@"%s\n", lua_tostring(threadState,-1));
            [threads removeObjectAtIndex:0];
            break;

        case LUA_ERRERR:
            NSLog(@"LUA_ERRERR: error while running the error handler function");
            NSLog(@"%s\n", lua_tostring(threadState,-1));
            [threads removeObjectAtIndex:0];
            break;

        case LUA_ERRRUN:
            NSLog(@"LUA_ERRRUN: a runtime error.");
            NSLog(@"%s\n", lua_tostring(threadState,-1));
            [threads removeObjectAtIndex:0];
            break;

        default:
            NSLog(@"Error Executing Threaded Script!");
            NSLog(@"%s\n", lua_tostring(threadState,-1));
            [threads removeObjectAtIndex:0];
            break;

    }

}

}

Whew that was a real pain to debug. BUT IT WORKS!!!!!

Cory R Leach