⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 perlcall.1

📁 视频监控网络部分的协议ddns,的模块的实现代码,请大家大胆指正.
💻 1
📖 第 1 页 / 共 5 页
字号:
allows only a single callback to be defined at any time. What werequire is a means of storing the mapping between the opened file andthe Perl subroutine we want to be called for that file..PPSay the i/o library has a function \f(CW\*(C`asynch_read\*(C'\fR which associates a Cfunction \f(CW\*(C`ProcessRead\*(C'\fR with a file handle \f(CW\*(C`fh\*(C'\fR\-\-this assumes that ithas also provided some routine to open the file and so obtain the filehandle..PP.Vb 1\&    asynch_read(fh, ProcessRead).Ve.PPThis may expect the C \fIProcessRead\fR function of this form.PP.Vb 7\&    void\&    ProcessRead(fh, buffer)\&    int fh;\&    char *      buffer;\&    {\&         ...\&    }.Ve.PPTo provide a Perl interface to this library we need to be able to mapbetween the \f(CW\*(C`fh\*(C'\fR parameter and the Perl subroutine we want called.  Ahash is a convenient mechanism for storing this mapping.  The codebelow shows a possible implementation.PP.Vb 1\&    static HV * Mapping = (HV*)NULL;\&\&    void\&    asynch_read(fh, callback)\&        int     fh\&        SV *    callback\&        CODE:\&        /* If the hash doesn\*(Aqt already exist, create it */\&        if (Mapping == (HV*)NULL)\&            Mapping = newHV();\&\&        /* Save the fh \-> callback mapping */\&        hv_store(Mapping, (char*)&fh, sizeof(fh), newSVsv(callback), 0);\&\&        /* Register with the C Library */\&        asynch_read(fh, asynch_read_if);.Ve.PPand \f(CW\*(C`asynch_read_if\*(C'\fR could look like this.PP.Vb 7\&    static void\&    asynch_read_if(fh, buffer)\&    int fh;\&    char *      buffer;\&    {\&        dSP;\&        SV ** sv;\&\&        /* Get the callback associated with fh */\&        sv =  hv_fetch(Mapping, (char*)&fh , sizeof(fh), FALSE);\&        if (sv == (SV**)NULL)\&            croak("Internal error...\en");\&\&        PUSHMARK(SP);\&        XPUSHs(sv_2mortal(newSViv(fh)));\&        XPUSHs(sv_2mortal(newSVpv(buffer, 0)));\&        PUTBACK;\&\&        /* Call the Perl sub */\&        call_sv(*sv, G_DISCARD);\&    }.Ve.PPFor completeness, here is \f(CW\*(C`asynch_close\*(C'\fR.  This shows how to removethe entry from the hash \f(CW\*(C`Mapping\*(C'\fR..PP.Vb 6\&    void\&    asynch_close(fh)\&        int     fh\&        CODE:\&        /* Remove the entry from the hash */\&        (void) hv_delete(Mapping, (char*)&fh, sizeof(fh), G_DISCARD);\&\&        /* Now call the real asynch_close */\&        asynch_close(fh);.Ve.PPSo the Perl interface would look like this.PP.Vb 4\&    sub callback1\&    {\&        my($handle, $buffer) = @_;\&    }\&\&    # Register the Perl callback\&    asynch_read($fh, \e&callback1);\&\&    asynch_close($fh);.Ve.PPThe mapping between the C callback and Perl is stored in the globalhash \f(CW\*(C`Mapping\*(C'\fR this time. Using a hash has the distinct advantage thatit allows an unlimited number of callbacks to be registered..PPWhat if the interface provided by the C callback doesn't contain aparameter which allows the file handle to Perl subroutine mapping?  Sayin the asynchronous i/o package, the callback function gets passed onlythe \f(CW\*(C`buffer\*(C'\fR parameter like this.PP.Vb 6\&    void\&    ProcessRead(buffer)\&    char *      buffer;\&    {\&        ...\&    }.Ve.PPWithout the file handle there is no straightforward way to map from theC callback to the Perl subroutine..PPIn this case a possible way around this problem is to predefine aseries of C functions to act as the interface to Perl, thus.PP.Vb 3\&    #define MAX_CB              3\&    #define NULL_HANDLE \-1\&    typedef void (*FnMap)();\&\&    struct MapStruct {\&        FnMap    Function;\&        SV *     PerlSub;\&        int      Handle;\&      };\&\&    static void  fn1();\&    static void  fn2();\&    static void  fn3();\&\&    static struct MapStruct Map [MAX_CB] =\&        {\&            { fn1, NULL, NULL_HANDLE },\&            { fn2, NULL, NULL_HANDLE },\&            { fn3, NULL, NULL_HANDLE }\&        };\&\&    static void\&    Pcb(index, buffer)\&    int index;\&    char * buffer;\&    {\&        dSP;\&\&        PUSHMARK(SP);\&        XPUSHs(sv_2mortal(newSVpv(buffer, 0)));\&        PUTBACK;\&\&        /* Call the Perl sub */\&        call_sv(Map[index].PerlSub, G_DISCARD);\&    }\&\&    static void\&    fn1(buffer)\&    char * buffer;\&    {\&        Pcb(0, buffer);\&    }\&\&    static void\&    fn2(buffer)\&    char * buffer;\&    {\&        Pcb(1, buffer);\&    }\&\&    static void\&    fn3(buffer)\&    char * buffer;\&    {\&        Pcb(2, buffer);\&    }\&\&    void\&    array_asynch_read(fh, callback)\&        int             fh\&        SV *    callback\&        CODE:\&        int index;\&        int null_index = MAX_CB;\&\&        /* Find the same handle or an empty entry */\&        for (index = 0; index < MAX_CB; ++index)\&        {\&            if (Map[index].Handle == fh)\&                break;\&\&            if (Map[index].Handle == NULL_HANDLE)\&                null_index = index;\&        }\&\&        if (index == MAX_CB && null_index == MAX_CB)\&            croak ("Too many callback functions registered\en");\&\&        if (index == MAX_CB)\&            index = null_index;\&\&        /* Save the file handle */\&        Map[index].Handle = fh;\&\&        /* Remember the Perl sub */\&        if (Map[index].PerlSub == (SV*)NULL)\&            Map[index].PerlSub = newSVsv(callback);\&        else\&            SvSetSV(Map[index].PerlSub, callback);\&\&        asynch_read(fh, Map[index].Function);\&\&    void\&    array_asynch_close(fh)\&        int     fh\&        CODE:\&        int index;\&\&        /* Find the file handle */\&        for (index = 0; index < MAX_CB; ++ index)\&            if (Map[index].Handle == fh)\&                break;\&\&        if (index == MAX_CB)\&            croak ("could not close fh %d\en", fh);\&\&        Map[index].Handle = NULL_HANDLE;\&        SvREFCNT_dec(Map[index].PerlSub);\&        Map[index].PerlSub = (SV*)NULL;\&\&        asynch_close(fh);.Ve.PPIn this case the functions \f(CW\*(C`fn1\*(C'\fR, \f(CW\*(C`fn2\*(C'\fR, and \f(CW\*(C`fn3\*(C'\fR are used toremember the Perl subroutine to be called. Each of the functions holdsa separate hard-wired index which is used in the function \f(CW\*(C`Pcb\*(C'\fR toaccess the \f(CW\*(C`Map\*(C'\fR array and actually call the Perl subroutine..PPThere are some obvious disadvantages with this technique..PPFirstly, the code is considerably more complex than with the previousexample..PPSecondly, there is a hard-wired limit (in this case 3) to the number ofcallbacks that can exist simultaneously. The only way to increase thelimit is by modifying the code to add more functions and thenrecompiling.  None the less, as long as the number of functions ischosen with some care, it is still a workable solution and in somecases is the only one available..PPTo summarize, here are a number of possible methods for you to considerfor storing the mapping between C and the Perl callback.IP "1. Ignore the problem \- Allow only 1 callback" 5.IX Item "1. Ignore the problem - Allow only 1 callback"For a lot of situations, like interfacing to an error handler, this maybe a perfectly adequate solution..IP "2. Create a sequence of callbacks \- hard wired limit" 5.IX Item "2. Create a sequence of callbacks - hard wired limit"If it is impossible to tell from the parameters passed back from the Ccallback what the context is, then you may need to create a sequence of Ccallback interface functions, and store pointers to each in an array..IP "3. Use a parameter to map to the Perl callback" 5.IX Item "3. Use a parameter to map to the Perl callback"A hash is an ideal mechanism to store the mapping between C and Perl..Sh "Alternate Stack Manipulation".IX Subsection "Alternate Stack Manipulation"Although I have made use of only the \f(CW\*(C`POP*\*(C'\fR macros to access valuesreturned from Perl subroutines, it is also possible to bypass thesemacros and read the stack using the \f(CW\*(C`ST\*(C'\fR macro (See perlxs for afull description of the \f(CW\*(C`ST\*(C'\fR macro)..PPMost of the time the \f(CW\*(C`POP*\*(C'\fR macros should be adequate, the mainproblem with them is that they force you to process the returned valuesin sequence. This may not be the most suitable way to process thevalues in some cases. What we want is to be able to access the stack ina random order. The \f(CW\*(C`ST\*(C'\fR macro as used when coding an \s-1XSUB\s0 is idealfor this purpose..PPThe code below is the example given in the section \fIReturning a listof values\fR recoded to use \f(CW\*(C`ST\*(C'\fR instead of \f(CW\*(C`POP*\*(C'\fR..PP.Vb 8\&    static void\&    call_AddSubtract2(a, b)\&    int a;\&    int b;\&    {\&        dSP;\&        I32 ax;\&        int count;\&\&        ENTER;\&        SAVETMPS;\&\&        PUSHMARK(SP);\&        XPUSHs(sv_2mortal(newSViv(a)));\&        XPUSHs(sv_2mortal(newSViv(b)));\&        PUTBACK;\&\&        count = call_pv("AddSubtract", G_ARRAY);\&\&        SPAGAIN;\&        SP \-= count;\&        ax = (SP \- PL_stack_base) + 1;\&\&        if (count != 2)\&            croak("Big trouble\en");\&\&        printf ("%d + %d = %d\en", a, b, SvIV(ST(0)));\&        printf ("%d \- %d = %d\en", a, b, SvIV(ST(1)));\&\&        PUTBACK;\&        FREETMPS;\&        LEAVE;\&    }.Ve.PPNotes.IP "1." 5Notice that it was necessary to define the variable \f(CW\*(C`ax\*(C'\fR.  This isbecause the \f(CW\*(C`ST\*(C'\fR macro expects it to exist.  If we were in an \s-1XSUB\s0 itwould not be necessary to define \f(CW\*(C`ax\*(C'\fR as it is already defined foryou..IP "2." 5The code.Sp.Vb 3\&        SPAGAIN;\&        SP \-= count;\&        ax = (SP \- PL_stack_base) + 1;.Ve.Spsets the stack up so that we can use the \f(CW\*(C`ST\*(C'\fR macro..IP "3." 5Unlike the original coding of this example, the returnedvalues are not accessed in reverse order.  So \f(CWST(0)\fR refers to thefirst value returned by the Perl subroutine and \f(CW\*(C`ST(count\-1)\*(C'\fRrefers to the last..Sh "Creating and calling an anonymous subroutine in C".IX Subsection "Creating and calling an anonymous subroutine in C"As we've already shown, \f(CW\*(C`call_sv\*(C'\fR can be used to invoke ananonymous subroutine.  However, our example showed a Perl scriptinvoking an \s-1XSUB\s0 to perform this operation.  Let's see how it can bedone inside our C code:.PP.Vb 1\& ...\&\& SV *cvrv = eval_pv("sub { print \*(AqYou will not find me cluttering any namespace!\*(Aq }", TRUE);\&\& ...\&\& call_sv(cvrv, G_VOID|G_NOARGS);.Ve.PP\&\f(CW\*(C`eval_pv\*(C'\fR is used to compile the anonymous subroutine, whichwill be the return value as well (read more about \f(CW\*(C`eval_pv\*(C'\fR in\&\*(L"eval_pv\*(R" in perlapi).  Once this code reference is in hand, itcan be mixed in with all the previous examples we've shown..SH "LIGHTWEIGHT CALLBACKS".IX Header "LIGHTWEIGHT CALLBACKS"Sometimes you need to invoke the same subroutine repeatedly.This usually happens with a function that acts on a list ofvalues, such as Perl's built-in \fIsort()\fR. You can pass acomparison function to \fIsort()\fR, which will then be invokedfor every pair of values that needs to be compared. The \fIfirst()\fRand \fIreduce()\fR functions from List::Util follow a similarpattern..PPIn this case it is possible to speed up the routine (oftenquite substantially) by using the lightweight callback \s-1API\s0.The idea is that the calling context only needs to becreated and destroyed once, and the sub can be calledarbitrarily many times in between..PPIt is usual to pass parameters using global variables \*(-- typically\&\f(CW$_\fR for one parameter, or \f(CW$a\fR and \f(CW$b\fR for two parameters \*(-- ratherthan via \f(CW@_\fR. (It is possible to use the \f(CW@_\fR mechanism if you knowwhat you're doing, though there is as yet no supported \s-1API\s0 forit. It's also inherently slower.).PPThe pattern of macro calls is like this:.PP.Vb 3\&    dMULTICALL;                 /* Declare local variables */\&    I32 gimme = G_SCALAR;       /* cont

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -