我有一个用C语言编写的Perl库,在XS文件中我声明了回调函数来从C代码调用Perl函数。从C代码(多线程)调用此函数时:
char *
callbackfunc(void *fun, char **args)
{
dSP;
int count,i;
char *s;
ENTER;
SAVETMPS;
PUSHMARK(SP);
for(i=0;args[i];++i) {
XPUSHs(sv_2mortal(newSVpv(args[i],0)));
}
PUTBACK;
count = call_sv(fun,G_SCALAR|G_EVAL);
SPAGAIN;
s = NULL;
if(count > 1)
croak("callback may return only single value\n");
if(count==1) {
s = strdup(POPp);
}
PUTBACK;
FREETMPS;
LEAVE;
return s;
}
我在 dSP 宏崩溃了:
#0 callbackfunc (fun=0x2416a58, args=0x7f3a0cfa9a10) at MyLibrary.xs:24
24 dSP;
在反汇编程序中,它看起来像找不到某些特定于线程的数据:
push %r15
push %r14
mov %rdi,%r14
push %r13
mov %rsi,%r13
push %r12
push %rbp
push %rbx
sub $0x8,%rsp
mov 0x2015dd(%rip),%rbx
mov (%rbx),%edi
callq 0x7f3a0e37f550 <pthread_getspecific@plt>
mov (%rbx),%esi
mov (%rax),%r15 // here is crash because %rax is 0x0
答案 0 :(得分:2)
你可能忘了告诉你的线程当前的Perl解释器。 perlembed
man page说:
只要没有创建interp的线程使用interp(使用perl_alloc()或更深奥的perl_clone()),也应该调用PERL_SET_CONTEXT(interp)。
另请注意,从C调用Perl不是线程安全的。确保正确锁定。
编辑:如果您没有自己创建解释器,则可以通过宏void *
向解释器获取PERL_GET_CONTEXT
。如果您只使用单个解释器,则可以向XS引导部分添加一些代码,以将此值存储在全局中。如果您有多个解释器(或希望在Windows上支持fork
),则必须在注册回调时跟踪当前的解释器。