2009-11-24 38 views
5

編輯:我已經創建了一個ticket爲此有數據替代這種做事的方式。在XS中創建線程回調

我有updated the code試圖使用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回調出現segfaults。

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 
+0

不應該有設置定時器並打印$時間的「休眠」? – tsee

+1

如果你的程序沒有阻塞,只是跳回到shell,這看起來像是一場嚴重的崩潰,否則perl不會完全失去控制。嘗試一個調試perl並在gdb中運行一些東西。 – tsee

+0

好吧我正在嘗試這個,但沒有什麼給了我一個完全不同的想法。我附上了這個問題的票。 – kthakore

回答

-1

我們已經找到了解決方案,使用Perl解釋器線程和線程::共享。請看看這些

Time.xs

而且,這裏是一個使用此代碼的腳本的例子。

TestTimer.pl

0

$時間需要一個共享變量 - 否則perl的作品與變量的單獨副本。

+0

恩......我不知道你指的是什麼。謹慎地放一些代碼? – kthakore

+0

在最後添加sleep 200,看看你是否看到任何輸出。 – weismat

+0

不行不行。它甚至沒有睡覺。 :( – kthakore

4

快速評論:

  • 不要使用Perl結構(SV,AV,HV,...),一個Perl解釋器對象的上下文之外。即請勿將其用作C級靜態數據。它將在線程上下文中爆炸。相信我,我一直在那裏。
  • 查看perlxs聯機幫助頁中的「安全地存儲XS中的靜態數據」部分。
  • 從perlapi的角度來看,你正在做的一些事情看起來相當不公開。但我不太確定。
+0

請參閱更新 – kthakore

0

我的首選處理方法是將數據存儲在PL_modglobal散列中。它會自動綁定到當前的解釋器。