chapter 27 Calling C from Lua

When we say that Lua can call C functions, this does not mean that Lua can
call any C function.
As we saw in the previous chapter, when C calls a Lua
function, it must follow a simple protocol to pass the arguments and to get the

results(error handle 压栈,function(get it from Lua)压栈 , 参数压栈).

Similarly, for Lua to call a C function, the C function must follow a

protocol to get its arguments and to return its results.Moreover, for Lua to call
a C function, we must register the function, that is, we must give its address to

Lua in an appropriate way.


When Lua calls a C function, it uses the same kind of stack that C uses to call
Lua. The C function gets its arguments from the stack and pushes the results
on the stack.


An important concept here is that the stack is not a global structure; each
function has its own private local stack. When Lua calls a C function, the first
argument will always be at index 1 of this local stack. Even when a C function
calls Lua code that calls the same (or another) C function again, each of these
invocations sees only its own private stack, with its first argument at index 1
.


27.1 C Functions

As a first example, let us see how to implement a simplified version of a function
that returns the sine of a given number:
static int l_sin (lua_State *L)

{
  double d = lua_tonumber(L, 1); /* get argument,local stack, 第一个参数的index always 1 */
  lua_pushnumber(L, sin(d)); /* push result */
  return 1; /* number of results */ 而有多少个结果,而不时结果,那结果是放什么地方,local Stack.
}


Any function registered with Lua must have this same prototype, defined as
lua_CFunction in lua.h:
typedef int (*lua_CFunction) (lua_State *L);


From the point of view of C, a C function gets as its single argument the Lua
state and returns an integer with the number of values it is returning in the
stack. Therefore, the function does not need to clear the stack before pushing its
results. After it returns, Lua automatically saves its results and clears its entire
stack


Before we can use this function from Lua, we must register it. We do this
little magic with lua_pushcfunction: it gets a pointer to a C function and
creates a value of type “function” that represents this function inside Lua. Once
registered, a C function behaves like any other function inside Lua
.


A quick-and-dirty way to test l_sin is to put its code directly into our basic
interpreter (Listing 25.1) and add the following lines right after the call to
luaL_openlibs
:


lua_pushcfunction(L, l_sin);
lua_setglobal(L, "mysin");


The first line pushes a value of type function; the second line assigns it to the
global variable mysin. After these modifications, you can use the new function
mysin in your Lua scripts. (In the next section, we will discuss better ways to
link new C functions with Lua.)


For a more professional sine function, we must check the type of its argument.
Here, the auxiliary library helps us. The luaL_checknumber function
checks whether a given argument is a number: in case of error, it throws an
informative error message; otherwise, it returns the number. The modification
to our function is minimal:


static int l_sin (lua_State *L) {
double d = luaL_checknumber(L, 1); //,local stack, 第一个参数的index always 1
lua_pushnumber(L, sin(d));
return 1; /* number of results */
}


With the above definition, if you call mysin('a'), you get the message
bad argument #1 to 'mysin' (number expected, got string)


Notice how luaL_checknumber automatically fills the message with the argument
number (#1), the function name (“mysin”), the expected parameter type
(number), and the actual parameter type (string).


As a more complex example, let us write a function that returns the contents
of a given directory. Lua does not provide this function in its standard libraries,
because ANSI C does not have functions for this job. Here, we will assume that
we have a POSIX compliant system. Our function—called dir in Lua, l_dir
in C—gets as argument a string with the directory path and returns an array

with the directory entries. For instance, a call dir("/home/lua") may return the
table {".","..","src","bin","lib"}.
In case of an error, the function returns
nil plus a string with the error message. The complete code for this function is in
Listing 27.1. Note the use of the luaL_checkstring function, from the auxiliary
library, which is the equivalent of luaL_checknumber for string
s.


(In extreme conditions, this implementation of l_dir may cause a small
memory leak. Three of the Lua functions that it calls can fail due to insufficient
memory: lua_newtable, lua_pushstring, and lua_settable. If any of these
functions fails, it will raise an error and interrupt l_dir, which therefore will
not call closedir. As we discussed earlier, on many programs this is not a big
problem: if the program runs out of memory, the best it can do is to shut down
anyway. Nevertheless, in Chapter 30 we will see an alternative implementation
for a directory function that corrects this problem.)


Listing 27.1. A function to read a directory:

#include <dirent.h>/dirent.h ent means entry.
#include <errno.h>
#include <string.h>
#include "lua.h"
#include "lauxlib.h"
static int l_dir (lua_State *L)
 {
    DIR *dir;
    struct dirent *entry;
    int i;
    const char *path = luaL_checkstring(L, 1);
    /* open directory */
    dir = opendir(path);
    if (dir == NULL) { /* error opening the directory? */
    lua_pushnil(L); /* return nil... */
    lua_pushstring(L, strerror(errno)); /* and error message */
    return 2; /* number of results */
    }
    /* create result table */
    lua_newtable(L);
    i = 1;
    while ((entry = readdir(dir)) != NULL) {
    lua_pushnumber(L, i++); /* push key */
    lua_pushstring(L, entry->d_name); /* push value */
    lua_settable(L, -3);//Set table 后会自动pop up the key-value pair? should be will
    }
    closedir(dir);
    return 1; /* table is already on top */
}


27.2 Continuations

Through lua_pcall and lua_call, a C function called from Lua can call Lua
back. Several functions in the standard library do that: table.sort can call an
order function; string.gsub can call a replacement function; pcall and xpcall
call functions in protected mode. If we remember that the main Lua code was
itself called from C (the host program), we have a call sequence like C (host)
calls Lua (script) that calls C (library) that calls Lua (callback)
..



Usually, Lua handles these sequences of calls without problems; after all,
this integration with C is a hallmark of the language. There is one situation,
however, where this interlacement can cause difficulties: coroutines.


Each coroutine in Lua has its own stack, which keeps information about
the pending calls of the coroutine. Specifically, the stack stores the return
address, the parameters, and the local variables of each call. For calls to Lua
functions, the interpreter uses an appropriate data structure to implement the
stack, which is called soft stack. For calls to C functions, however, the interpreter
must use the C stack, too. After all, the return address and the local variables
of a C function live in the C stack
.


It is easy for the interpreter to have multiple soft stacks, but the runtime
of ANSI C has only one internal stack. Therefore, coroutines in Lua cannot
suspend the execution of a C function: if there is a C function in the call path
from a resume to its respective yield, Lua cannot save the state of that C function
to restore it in the next resume.
Consider the next example, in Lua 5.1:


co = coroutine.wrap(function (a)
return pcall(function (x)
                    coroutine.yield(x[1])
                    return x[3]
                     end, a)
             end)
print(co({10, 3, -8, 15}))
--> false attempt to yield across metamethod/C-call boundary

when call co, will resume the coroutine and pcall will be excute, as pcall is exactly a C function, so will call back

to Lua,when excute in Lua, and hit yield, as in Lua5.1, can't suspend C call, so willpropagated the error to Lua.

will not hand back to C host system.


如果在Lua5.2 excute,it works without any issue.

----------recall these function first-----------------------------

Like coroutine.create,thecoroutine.wrap function also creates a coroutine,but instead of returning the coroutine itself,it returns a function that, when called, resumes the coroutine.Any arguments passed to this functiongo as extra arguments tocoroutine.resume.coroutine.wrap returns all the values returned bycoroutine.resume,except the first one (the boolean error code).Unlikecoroutine.resume,coroutine.wrap does not catch errors;any error is propagated to the caller.


pcall Calls functionf withthe given arguments inprotected mode.This means that any error inside f is not propagated;instead,pcall catches the errorand returns a status code.Its first result is the status code (a boolean),which is true if the call succeeds without errors.In such case,pcall also returns all results from the call,after this first result.In case of any error,pcall returnsfalse plus the error message.

--------------------------------------============================




The pcall function is a C function; therefore, Lua cannot suspend it, because
there is no way in ANSI C to suspend a C function and resume it later
.


Lua 5.2 ameliorated that difficulty with continuations.Lua 5.2 implements
yields using long jumps, in the same way that it implements errors. A long jump
simply throws away any information about C functions in the C stack, so it is
impossible to resume those functions. However, a C function foo can specify a
continuation function foo-c, which is another C function to be called when it is
time to resume foo.
That is, when the interpreter detects that it should resume
foo, but that a long jump threw away the entry for foo in the C stack, it calls
foo-c instead


To make things a little more concrete, let us see an example: the implementation
of pcall. In Lua 5.1, this function had the following code:


static int luaB_pcall (lua_State *L) { //luaB_pcall 最后会register to Lua as pcall in gloabal env.
    int status;
    luaL_checkany(L, 1); /* at least one parameter,pcall 是用来调用Lua function,所以stack里面至少要有被调用函数 */
    status = lua_pcall(L, lua_gettop(L) - 1, LUA_MULTRET, 0);//lua_gettop(L) - 1 减去一个function,剩下的就是参数个数拉,,, LUA_MULTRET 不确定返回多少个value,那就用个这个参数告诉Lua 所有结果都返回,,,

    lua_pushboolean(L, (status == 0)); /* status */
    lua_insert(L, 1); /* status is first result */
    return lua_gettop(L); /* return status + all results */
}



void lua_insert (lua_State *L, int index);

Moves the top element into the given valid index,shifting up the elements above this index to open space.This function cannot be called with a pseudo-index,because a pseudo-index is not an actual stack position.

    lua_pushboolean(L, (status == 0)); /* status */  把true or false 压到top of the Stack
    lua_insert(L, 1); /* status is first result */
  insert of top element of the stack to the first position of the Stack.


  return lua_gettop(L); /* return status + all results */ 不是返回结果是,结果的个数,但要加上执行的status, so

if the called lua function will return 3 resule, then lua_gettop(L) is 4.



If the function being called through lua_pcall yielded, it would be impossible to
resume luaB_pcall later. Therefore, the interpreter raised an error whenever
we attempted to yield inside a protected call. Lua 5.2 implements pcall roughly
like in Listing 27.2.2 There are three differences from the Lua 5.1 version: first,
the new version replaced the call to lua_pcall by a call to lua_pcallk; second, it
grouped everything done after that call in a new auxiliary function finishpcall;
the third difference is the function pcallcont, the last argument to lua_pcallk,
which is the continuation function
.


If there are no yields, lua_pcallk works exactly like lua_pcall. If there is
a yield, then things are quite different. If a function called by lua_pcall tries
to yield, Lua 5.2 raises an error, like Lua 5.1
,也就是lua_pcall 在Lua5.2 也是存在的,看你在C 里面怎么调用,而Lua5.2 用的是 lua_pcallk
. But when a function called by
lua_pcallk yields, there are no errors: Lua does a long jump and throws away
the entry for luaB_pcall in the C stack, but it keeps in the soft stack of the
coroutine a reference to the continuation function<这个是关键keep the continuation function in the soft stack >, pcallcont. Later, when the
interpreter detects that it should return to luaB_pcall (which is impossible,也就是要返回 luaB_pcall 的yield 点其实是不可能的拉,,,), it
instead calls the continuation function pcallcont
.


Unlike luaB_pcall, the continuation function pcallcont cannot get the return
value from lua_pcallk <because impossible return back to luaB_pcall>.

So, Lua provides a special function to return a
status of the call: lua_getctx. When called from a regular Lua function (a case
that does not happen in our example), lua_getctx returns LUA_OK. When called
regularly from a continuation function, it returns LUA_YIELD. The continuation
function can be called also in some cases of errors; in that case, lua_getctx returns
the error status, which is the same value that lua_pcallk would return.


int lua_pcallk (lua_State *L,
                int nargs,
                int nresults,
                int errfunc,
                int ctx,
                lua_CFunction k);
可以看到我们传入了 int ctx, lua_getctx 就是通过这个ctx获取yield 后resume 执行后的结果的,否则如果只是普通的

函数执行流程,status is returned from   lua_pcallk


=================================================================

http://luaforge.net/tags/

http://luaforge.net/projects/luabinaries/

in these website you can download the Lua5.2.dll etc libray....

=================================================================


Listing 27.2. Implementation of pcall with continuations:

static int finishpcall (lua_State *L, int status)
{
    lua_pushboolean(L, status); /* first result (status) */
    lua_insert(L, 1); /* put first result in first slot */
    return lua_gettop(L);
}
    static int pcallcont (lua_State *L)

  {
    int status = lua_getctx(L, NULL);
    return finishpcall(L, (status == LUA_YIELD));
    }
    static int luaB_pcall (lua_State *L)

{
    int status;
    luaL_checkany(L, 1);
    status = lua_pcallk(L, lua_gettop(L) - 2, LUA_MULTRET, 0,
    0, pcallcont);
    return finishpcall(L, (status == LUA_OK));//如果是yield ,是不可能执行到到这里的,becuase ,longjump will throw

                                            //away the information about luaB_pcall , instead will excute the pcallcont

}


Besides the status of the call, lua_getctx can also return a context information
(hence its name, from get context). The fifth parameter to lua_pcallk is an
arbitrary integer that can be retrieved by the second parameter of lua_getctx,

a pointer to integer. This integer value allows the original function to pass some
arbitrary information directly to its continuation. It can pass additional information
through the Lua stack. (Our example does not use this facility.)




int lua_getctx (lua_State *L, int *ctx);

This function is called by a continuation function (see §4.7)to retrieve the status of the thread and a context information.

When called in the original function,lua_getctx always returnsLUA_OKand does not change the value of its argument ctx.When called inside a continuation function,lua_getctx returnsLUA_YIELD and setsthe value of ctx to be the context information(the value passed as thectx argument to the callee together with the continuation function).

When the callee is lua_pcallk,Lua may also call its continuation functionto handle errors during the call.That is, upon an error in the function called bylua_pcallk,Lua may not return to the original functionbut instead may call the continuation function.In that case, a call tolua_getctx will return the error code(the value that would be returned bylua_pcallk);the value of ctx will be set to the context information,as in the case of a yield.


lua_pcallk 第5个参数是ctx is just an int, but in lua_getctx the second parameter is an int pointer....


we need to return back to our question:

co = coroutine.wrap(function (a)
return pcall(function (x)
                    coroutine.yield(x[1])
                    return x[3]
                     end, a)
             end)
print(co({10, 3, -8, 15}))


because pcall is a C function, when is called, will  call the Lua function, plus a table argument. right !!

the Lua function and the argument will be push into the Stack. then excute the Lua funciton , in the Lua function

there is yield command, so the thread need to interrupt, then what's thepcallcont here,??/ how to resume process

when in lua i call corotinue.resume ??? how , the book still not interpret,,,,,,,,,,,,,,,,,,,,,

will continue back when possible............





The continuation system of Lua 5.2 is an ingenious mechanism to support
yields, but it is not a panacea. Some C functions would need to pass too much
context to their continuations. Examples include table.sort, which uses the
C stack for recursion, and string.gsub, which must keep track of captures
and a buffer for its partial result. Although it is possible to rewrite them in
a “yieldable” way, the gains do not seem to be worth the extra complexity.


27.3 C Modules

A Lua module is a chunk that defines several Lua functions and stores them
in appropriate places, typically as entries in a table. A C module for Lua
mimics this behavior. Besides the definition of its C functions, it must also
define a special function that plays the role of the main chunk in a Lua library.
This function should register all C functions of the module and store them in
appropriate places, again typically as entries in a table. Like a Lua main chunk,
it should also initialize anything else that needs initialization in the module.


Lua perceives C functions through this registration process. Once a C function is represented and stored in Lua, Lua calls it through a direct reference to   its address (which is what we give to Lua when we register a function).In other
words, Lua does not depend on a function name, package location, or visibility
rules to call a function, once it is registered.
Typically, a C module has one single
public (extern) function, which is the function that opens the library.
All other
functions can be private, declared as static in C.


When you extend Lua with C functions, it is a good idea to design your code
as a C module, even when you want to register only one C function: sooner
or later (usually sooner) you will need other functions. As usual, the auxiliary
library offers a helper function for this job. The luaL_newlib macro takes a list
of C functions with their respective names and registers all of them inside a
new table. As an example, suppose we want to create a library with the l_dir
function that we defined earlier. First, we must define the library functions:


static int l_dir (lua_State *L) {
<as before>
}


Next, we declare an array with all functions in the module with their respective
names. This array has elements of type luaL_Reg, which is a structure with two
fields: a function name (a string) and a function pointer.


static const struct luaL_Reg mylib [] = {
{"dir", l_dir},
{NULL, NULL} /* sentinel */
};


In our example, there is only one function (l_dir) to declare. The last pair in
the array is always {NULL,NULL}, to signal its end. Finally, we declare a main
function, using luaL_newlib:
int luaopen_mylib (lua_State *L) {
luaL_newlib(L, mylib);
return 1;
}


The call to luaL_newlib creates a new table and fills it with the pairs name–
function specified by the array mylib. When it returns, luaL_newlib leaves
on the stack the new table wherein it opened the library. The luaopen_mylib
function then returns 1 to return this table to Lua. 也就是 luaL_newlib 执行完后,其创建的table 将push to the

stack,that's index is 1....



After finishing the library, we must link it to the interpreter. The most convenient
way to do it is with the dynamic linking facility, if your Lua interpreter
supports this facility. In this case, you must create a dynamic library with your
code (mylib.dll in Windows, mylib.so in Linux-like systems) and put it somewhere
in the C path. After these steps, you can load your library directly from
Lua, with require:


local mylibTable = require "mylib"  , mylibTable  就是uaL_newlib 执行完后,其创建的table



This call links the dynamic library mylib with Lua, finds the luaopen_mylib
function,看来不单函数前面要一致,命名还有约定, ,
registers it as a C function, and calls it, opening the module. (This behavior explains why luaopen_mylib must have the same prototype as any
other C function.)  require "mylib" -->根据命名约定,会去寻找  luaopen_mylib 这样的一个函数,而这个函数必须是:


Any function registered with Lua must have this same prototype, defined as
lua_CFunction in lua.h:
typedef int (*lua_CFunction) (lua_State *L);



The dynamic linker must know the name of the luaopen_mylib function in
order to find it. It will always look for luaopen_ concatenated with the name
of the module. Therefore, if our module is called mylib, that function must be
called luaopen_mylib
. 果然没猜错,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,


If your interpreter does not support dynamic linking, then you have to recompile
Lua with your new library. Besides this recompilation, you need some
way of telling the stand-alone interpreter that it should open this library when
it opens a new state. A simple way to do this is to add luaopen_mylib into the
list of standard libraries to be opened by luaL_openlibs, in file linit.c
.



 when over this chapter ,you can review the Chapter15  P172...... about module ...

ie:

If require cannot find a Lua file with the module name, it searches for
a C library with the module name. If it finds a C library, it loads it with
package.loadlib (which we discussed in Section 8.3), looking for a function
called luaopen_modname. The loader in this case is the result of loadlib, that
is, the function luaopen_modname represented as a Lua function.






















































































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值