[Pyrex] Pyrex initialization question.

Blake Winton bwinton at latte.ca
Fri Jan 7 20:45:03 CET 2005


As some of you may remember, I'm trying to write a DLL that calls a 
Pyrex extension module, or, as ascii art:

+------------+
| Palm's exe |
+------------+
      | (loads and unloads
      V  not under my control)
+----------------------------------+
|             My DLL               |
| (with my pyrex module linked in) |
+----------------------------------+
      | (calls into)
      V
+----------------+
| My Python code |
+----------------+
      | (uses types from)
      V
+-----------------+
| My Pyrex module |
+-----------------+

I'm quite a bit further than I was the last time I posted, but I've hit 
a new snag.  In my main C file, I've got a DLL entry point which makes 
the following series of calls:

COND_API DWORD GetConduitVersion()
{
   DWORD rc=0;
   PyGILState_STATE state;
   check_init();
   state = PyGILState_Ensure();
   rc = PyxGetConduitVersion();
   PyGILState_Release(state);
   return rc;
}

The check_init method [attached below at 0] (which I stole almost 
verbatim from py2exe) checks a couple of things, calls Py_Initialize, 
sets up the PYTHONPATH to include a zip file, and then calls initbtest() 
to initialize my pyrex module.

A twist is that since I'm in a dll, I'm calling Py_Initialize and 
initbtest more than once.

My initbtest [attached below at 1] function is failing, hard, on the 
following line the second time I call it:
   if (PyObject_SetAttrString(__pyx_m, "PyxSyncPrefs", (PyObject 
*)&__pyx_type_5btest_PyxSyncPrefs) < 0)

Now, I've printed out the values of __pyx_m, and 
&__pyx_type_5btest_PyxSyncPrefs, and they both seem fine.
(0x135a4f0 and 0x1425228 the first time initbtest is called,
  0x135a4f0 and 0x1585228 the second time initbtest is called.)

Does anyone have any suggestions on where I can look to find out why 
this method is failing the second time, or how I might modify initbtest 
to not fail?

As a side note, I tried not calling initbtest if Py_IsInitialized, but I 
get another error later on when I try to use the value of 
__pyx_ptype_5btest_PyxSyncPrefs, because it's not set.  (It gets set in 
initbtest, in the line:
   __pyx_ptype_5btest_PyxSyncPrefs = &__pyx_type_5btest_PyxSyncPrefs;
It would be nice if I could call a function which just set that 
variable, and assumed that the rest of my extension was already loaded.

(Looking a little further, I find that Marc Lemburg says:
"extension modules can typically only initialize themselves *once*" 
which indicates that I really shouldn't be calling initbtest more than 
once, but since my dll is getting unloaded, I'm losing the values of my 
static variables, and initbtest seems to be the only thing that re-sets 
them.  So, I'ld love to hear a solution which will let me set the proper 
value for __pyx_ptype_5btest_PyxSyncPrefs from somewhere.)

Thanks,
Blake.
-- 
[0] int check_init()
{
   if (!have_init) {
     EnterCriticalSection(&csInit);
     // Check the flag again - another thread may have beat us to it!
     if (!have_init) {
       PyObject *frozen;
       /* If Python had previously been initialized, we must use
         PyGILState_Ensure normally.  If Python has not been initialized,
         we must leave the thread state unlocked, so other threads can
         call in.
       */
       PyGILState_STATE restore_state = PyGILState_UNLOCKED;
       if (Py_IsInitialized())
         restore_state = PyGILState_Ensure();
       // a little DLL magic.  Set sys.frozen='dll'
       init_with_instance(gInstance, "dll");
       frozen = PyInt_FromLong((LONG)gInstance);
       if (frozen) {
         PySys_SetObject("frozendllhandle", frozen);
         Py_DECREF(frozen);
       }
       // Now run the generic script - this always returns in a DLL.
       initbtest();
       have_init = TRUE;
       // Reset the thread-state, so any thread can call in
       PyGILState_Release(restore_state);
     }
     LeaveCriticalSection(&csInit);
   }
   return gPythoncom != NULL;
}

[1] DL_EXPORT(void) initbtest(void) {
   __pyx_m = Py_InitModule4("btest", __pyx_methods, 0, 0, 
PYTHON_API_VERSION);
   if (!__pyx_m) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; goto 
__pyx_L1;};
   __pyx_b = PyImport_AddModule("__builtin__");
   if (!__pyx_b) {__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; goto 
__pyx_L1;};
   if (PyObject_SetAttrString(__pyx_m, "__builtins__", __pyx_b) < 0) 
{__pyx_filename = __pyx_f[0]; __pyx_lineno = 1; goto __pyx_L1;};
   if (__Pyx_InternStrings(__pyx_intern_tab) < 0) {__pyx_filename = 
__pyx_f[0]; __pyx_lineno = 1; goto __pyx_L1;};
   if (__Pyx_InitStrings(__pyx_string_tab) < 0) {__pyx_filename = 
__pyx_f[0]; __pyx_lineno = 1; goto __pyx_L1;};
   if (PyType_Ready(&__pyx_type_5btest_PyxSyncPrefs) < 0) 
{__pyx_filename = __pyx_f[0]; __pyx_lineno = 81; goto __pyx_L1;}

   // Fails on the next line!!!
   if (PyObject_SetAttrString(__pyx_m, "PyxSyncPrefs", (PyObject 
*)&__pyx_type_5btest_PyxSyncPrefs) < 0)
   {
     __pyx_filename = __pyx_f[0];
     __pyx_lineno = 81;
      goto __pyx_L1;
   }
   SystemError( 0, "initbtest 2" );
   __pyx_ptype_5btest_PyxSyncPrefs = &__pyx_type_5btest_PyxSyncPrefs;

   SystemError( 0, "initbtest 3" );
   /* "C:\VSS\Personal\svn\pEdit\conduit\btest.pyx":137 */
   return;
   __pyx_L1:;
   SystemError( 0, "initbtest 4" );
   __Pyx_AddTraceback("btest");
   SystemError( 0, "initbtest 5" );
}




More information about the Pyrex mailing list