在 XS 中创建线程回调
编辑:我为此创建了一张票,其中包含有关替代方案的数据这种做事方式。
我已经更新了代码试图使用MY_CXT的回调,因为gcxt没有存储在线程。然而,这在 ENTER 处出现段错误。
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifndef aTHX_
#define aTHX_
#endif
#ifdef USE_THREADS
#define HAVE_TLS_CONTEXT
#endif
/* For windows */
#ifndef SDL_PERL_DEFINES_H
#define SDL_PERL_DEFINES_H
#ifdef HAVE_TLS_CONTEXT
PerlInterpreter *parent_perl = NULL;
extern PerlInterpreter *parent_perl;
#define GET_TLS_CONTEXT parent_perl = PERL_GET_CONTEXT;
#define ENTER_TLS_CONTEXT \
PerlInterpreter *current_perl = PERL_GET_CONTEXT; \
PERL_SET_CONTEXT(parent_perl); { \
PerlInterpreter *my_perl = parent_perl;
#define LEAVE_TLS_CONTEXT \
} PERL_SET_CONTEXT(current_perl);
#else
#define GET_TLS_CONTEXT /* TLS context not enabled */
#define ENTER_TLS_CONTEXT /* TLS context not enabled */
#define LEAVE_TLS_CONTEXT /* TLS context not enabled */
#endif
#endif
#include <SDL.h>
#define MY_CXT_KEY "SDL::Time::_guts" XS_VERSION
typedef struct {
void* data;
SV* callback;
Uint32 retval;
} my_cxt_t;
static my_cxt_t gcxt;
START_MY_CXT
static Uint32 add_timer_cb ( Uint32 interval, void* param )
{
ENTER_TLS_CONTEXT
dMY_CXT;
dSP;
int back;
ENTER; //SEGFAULTS RIGHT HERE!
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(interval)));
PUTBACK;
if (0 != (back = call_sv(MY_CXT.callback,G_SCALAR))) {
SPAGAIN;
if (back != 1 ) Perl_croak (aTHX_ "Timer Callback failed!");
MY_CXT.retval = POPi;
} else {
Perl_croak(aTHX_ "Timer Callback failed!");
}
FREETMPS;
LEAVE;
LEAVE_TLS_CONTEXT
dMY_CXT;
return MY_CXT.retval;
}
MODULE = SDL::Time PACKAGE = SDL::Time PREFIX = time_
BOOT:
{
MY_CXT_INIT;
}
SDL_TimerID
time_add_timer ( interval, cmd )
Uint32 interval
void *cmd
PREINIT:
dMY_CXT;
CODE:
MY_CXT.callback=cmd;
gcxt = MY_CXT;
RETVAL = SDL_AddTimer(interval,add_timer_cb,(void *)cmd);
OUTPUT:
RETVAL
void
CLONE(...)
CODE:
MY_CXT_CLONE;
当我进入 ENTER 进行回调时,此段错误就会出现。
use SDL;
use SDL::Time;
SDL::init(SDL_INIT_TIMER);
my $time = 0;
SDL::Timer::add_timer(100, sub { $time++; return $_[0]} );
sleep(10);
print "Never Prints";
输出
$
应该是
$ Never Prints
EDIT: I have created a ticket for this which has data on an alternative to this way of doing things.
I have updated the code in an attempt to use MY_CXT's callback as gcxt was not storing across threads. However this segfaults at ENTER.
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifndef aTHX_
#define aTHX_
#endif
#ifdef USE_THREADS
#define HAVE_TLS_CONTEXT
#endif
/* For windows */
#ifndef SDL_PERL_DEFINES_H
#define SDL_PERL_DEFINES_H
#ifdef HAVE_TLS_CONTEXT
PerlInterpreter *parent_perl = NULL;
extern PerlInterpreter *parent_perl;
#define GET_TLS_CONTEXT parent_perl = PERL_GET_CONTEXT;
#define ENTER_TLS_CONTEXT \
PerlInterpreter *current_perl = PERL_GET_CONTEXT; \
PERL_SET_CONTEXT(parent_perl); { \
PerlInterpreter *my_perl = parent_perl;
#define LEAVE_TLS_CONTEXT \
} PERL_SET_CONTEXT(current_perl);
#else
#define GET_TLS_CONTEXT /* TLS context not enabled */
#define ENTER_TLS_CONTEXT /* TLS context not enabled */
#define LEAVE_TLS_CONTEXT /* TLS context not enabled */
#endif
#endif
#include <SDL.h>
#define MY_CXT_KEY "SDL::Time::_guts" XS_VERSION
typedef struct {
void* data;
SV* callback;
Uint32 retval;
} my_cxt_t;
static my_cxt_t gcxt;
START_MY_CXT
static Uint32 add_timer_cb ( Uint32 interval, void* param )
{
ENTER_TLS_CONTEXT
dMY_CXT;
dSP;
int back;
ENTER; //SEGFAULTS RIGHT HERE!
SAVETMPS;
PUSHMARK(SP);
XPUSHs(sv_2mortal(newSViv(interval)));
PUTBACK;
if (0 != (back = call_sv(MY_CXT.callback,G_SCALAR))) {
SPAGAIN;
if (back != 1 ) Perl_croak (aTHX_ "Timer Callback failed!");
MY_CXT.retval = POPi;
} else {
Perl_croak(aTHX_ "Timer Callback failed!");
}
FREETMPS;
LEAVE;
LEAVE_TLS_CONTEXT
dMY_CXT;
return MY_CXT.retval;
}
MODULE = SDL::Time PACKAGE = SDL::Time PREFIX = time_
BOOT:
{
MY_CXT_INIT;
}
SDL_TimerID
time_add_timer ( interval, cmd )
Uint32 interval
void *cmd
PREINIT:
dMY_CXT;
CODE:
MY_CXT.callback=cmd;
gcxt = MY_CXT;
RETVAL = SDL_AddTimer(interval,add_timer_cb,(void *)cmd);
OUTPUT:
RETVAL
void
CLONE(...)
CODE:
MY_CXT_CLONE;
This segfaults as soon as I go into ENTER for the callback.
use SDL;
use SDL::Time;
SDL::init(SDL_INIT_TIMER);
my $time = 0;
SDL::Timer::add_timer(100, sub { $time++; return $_[0]} );
sleep(10);
print "Never Prints";
Output is
$
it should be
$ Never Prints
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
快速评论:
Quick comments:
$time 需要是一个共享变量 - 否则 perl 使用该变量的单独副本。
$time needs to be a shared variable - otherwise perl works with separate copies of the variable.
我处理此问题的首选方法是将数据存储在 PL_modglobal 哈希中。它会自动绑定到当前的解释器。
My preferred way of handling this is storing the data in the PL_modglobal hash. It's automatically tied to the current interpreter.
我们已经找到了使用 Perl 解释器线程和threads::shared 的解决方案。请参阅这些
Time.xs
这里还有一个使用此代码的脚本示例。
TestTimer.pl
We have found a solution to this using Perl interpreter threads and threads::shared. Please see these
Time.xs
Also here is an example of a script using this code.
TestTimer.pl