在 XS 中创建线程回调

发布于 2024-08-12 06:25:25 字数 2796 浏览 3 评论 0原文

编辑:我为此创建了一张,其中包含有关替代方案的数据这种做事方式。

我已经更新了代码试图使用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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

软糯酥胸 2024-08-19 06:25:25

快速评论:

  • 不要在 Perl 解释器对象的上下文之外使用 Perl 结构(SV、AV、HV...)。即不要将其用作C 级静态数据。它会在线程上下文中爆炸。相信我,我去过那里。
  • 查看 perlxs 联机帮助页中的“在 XS 中安全存储静态数据”部分。
  • 从 perlapi 的角度来看,你正在做的一些事情看起来相当非公开。不过我不太确定。

Quick comments:

  • Do not use Perl structs (SV, AV, HV, ...) outside of the context of a Perl interpreter object. I.e. do not use it as C-level static data. It will blow up in a threading context. Trust me, I've been there.
  • Check out the "Safely Storing Static Data in XS" section in the perlxs manpage.
  • Some of that stuff you're doing looks rather non-public from the point of view of the perlapi. I'm not quite certain, though.
别靠近我心 2024-08-19 06:25:25

$time 需要是一个共享变量 - 否则 perl 使用该变量的单独副本。

$time needs to be a shared variable - otherwise perl works with separate copies of the variable.

月棠 2024-08-19 06:25:25

我处理此问题的首选方法是将数据存储在 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.

乱世争霸 2024-08-19 06:25:25

我们已经找到了使用 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文