5

編集:私は、この方法の代替方法に関するデータを持つチケットを作成しました。

gcxt がスレッド間で保存されていなかったため、MY_CXT のコールバックを使用するためにコードを更新しました。ただし、これは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
4

4 に答える 4

4

簡単なコメント:

  • Perl インタプリタ オブジェクトのコンテキスト外で Perl 構造体 (SV、AV、HV、...) を使用しないでください。つまり、C レベルの静的データとして使用しないでください。スレッドコンテキストで爆発します。私を信じてください、私はそこにいました。
  • perlxsマンページの「XS に静的データを安全に保存する」セクションを調べてください。
  • あなたがやっていることのいくつかは、perlapi の観点からはかなり非公開に見えます。よくわかりませんが。
于 2009-11-24T17:06:53.550 に答える
0

$time は共有変数である必要があります - そうでない場合、perl は変数の個別のコピーで動作します。

于 2009-11-24T16:26:28.390 に答える
0

これを処理する私の好みの方法は、データをPL_modglobalハッシュに格納することです。現在のインタープリターに自動的に関連付けられます。

于 2009-11-27T20:43:38.570 に答える
-1

Perl インタープリターのスレッドとスレッド::共有を使用して、これに対する解決策を見つけました。これらをご覧ください

時間.xs

また、このコードを使用したスクリプトの例を次に示します。

TestTimer.pl

于 2010-01-04T20:53:56.500 に答える