/alps/pcitool

To get this branch, use:
bzr branch http://suren.me/webbzr/alps/pcitool

« back to all changes in this revision

Viewing changes to pcilib/py.c

  • Committer: Suren A. Chilingaryan
  • Date: 2016-03-06 00:51:58 UTC
  • Revision ID: csa@suren.me-20160306005158-j8x0bog49ri0pzxn
Fix more threading problems in Python3

Show diffs side-by-side

added added

removed removed

Lines of Context:
34
34
struct pcilib_py_s {
35
35
    int finalyze;                       /**< Indicates, that we are initialized from wrapper and should not destroy Python resources in destructor */
36
36
    PyObject *main_module;              /**< Main interpreter */
 
37
    PyObject *pywrap_module;            /**< Pcilib python wrapper */
 
38
    PyObject *threading_module;         /**< Threading module */
37
39
    PyObject *global_dict;              /**< Dictionary of main interpreter */
38
 
    PyObject *pcilib_pywrap;            /**< pcilib wrapper module */
 
40
    PyObject *pcilib_pywrap;            /**< pcilib wrapper context */
39
41
    pcilib_script_t *script_hash;       /**< Hash with loaded scripts */
40
42
    
41
43
# if PY_MAJOR_VERSION >= 3
42
 
    pthread_t pth;
43
 
    pthread_cond_t cond;
44
 
    pthread_mutex_t lock;
 
44
    int status;                         /**< Indicates if python was initialized successfuly (0) or error have occured */
 
45
    pthread_t pth;                      /**< Helper thread for Python initialization */
 
46
    pthread_cond_t cond;                /**< Condition informing about initialization success and request for clean-up */
 
47
    pthread_mutex_t lock;               /**< Condition lock */
 
48
 
 
49
//    PyInterpreterState *istate;
 
50
//    PyThreadState *tstate;
45
51
# endif /* PY_MAJOR_VERSION > 3 */
46
52
};
47
53
#endif /* HAVE_PYTHON */
126
132
}
127
133
 
128
134
#ifdef HAVE_PYTHON
 
135
static int pcilib_py_load_default_modules(pcilib_t *ctx) {
 
136
    PyGILState_STATE gstate = PyGILState_Ensure();
 
137
 
 
138
    ctx->py->main_module = PyImport_AddModule("__parser__");
 
139
    if (!ctx->py->main_module) {
 
140
        PyGILState_Release(gstate);
 
141
        pcilib_python_warning("Error importing python parser");
 
142
        return PCILIB_ERROR_FAILED;
 
143
    }
 
144
 
 
145
    ctx->py->global_dict = PyModule_GetDict(ctx->py->main_module);
 
146
    if (!ctx->py->global_dict) {
 
147
        PyGILState_Release(gstate);
 
148
        pcilib_python_warning("Error locating global python dictionary");
 
149
        return PCILIB_ERROR_FAILED;
 
150
    }
 
151
 
 
152
    ctx->py->pywrap_module = PyImport_ImportModule(PCILIB_PYTHON_WRAPPER);
 
153
    if (!ctx->py->pywrap_module) {
 
154
        PyGILState_Release(gstate);
 
155
        pcilib_python_warning("Error importing pcilib python wrapper");
 
156
        return PCILIB_ERROR_FAILED;
 
157
    }
 
158
 
 
159
    /**
 
160
     * We need to load threading module here, otherwise if any of the scripts
 
161
     * will use threading, on cleanup Python3 will complain:
 
162
     * Exception KeyError: KeyError(140702199305984,) in <module 'threading' from '/usr/lib64/python3.3/threading.py'> ignored
 
163
     * The idea to load threading module is inspired by
 
164
     * http://stackoverflow.com/questions/8774958/keyerror-in-module-threading-after-a-successful-py-test-run
 
165
     */
 
166
    ctx->py->threading_module = PyImport_ImportModule("threading");
 
167
    if (!ctx->py->threading_module) {
 
168
        PyGILState_Release(gstate);
 
169
        pcilib_python_warning("Error importing threading python module");
 
170
        return PCILIB_ERROR_FAILED;
 
171
    }
 
172
        
 
173
    PyObject *mod_name = PyUnicode_FromString(PCILIB_PYTHON_WRAPPER);
 
174
    PyObject *pyctx = PyCapsule_New(ctx, "pcilib", NULL);
 
175
    ctx->py->pcilib_pywrap = PyObject_CallMethodObjArgs(ctx->py->pywrap_module, mod_name, pyctx, NULL);
 
176
    Py_XDECREF(pyctx);
 
177
    Py_XDECREF(mod_name);
 
178
        
 
179
    if (!ctx->py->pcilib_pywrap) {
 
180
        PyGILState_Release(gstate);
 
181
        pcilib_python_warning("Error initializing python wrapper");
 
182
        return PCILIB_ERROR_FAILED;
 
183
    }
 
184
 
 
185
    PyGILState_Release(gstate);
 
186
    return 0;
 
187
}
 
188
 
 
189
static void pcilib_py_clean_default_modules(pcilib_t *ctx) {
 
190
    PyGILState_STATE gstate;
 
191
 
 
192
    gstate = PyGILState_Ensure();
 
193
 
 
194
    if (ctx->py->pcilib_pywrap) Py_DECREF(ctx->py->pcilib_pywrap);
 
195
 
 
196
    if (ctx->py->threading_module) Py_DECREF(ctx->py->threading_module);
 
197
    if (ctx->py->pywrap_module) Py_DECREF(ctx->py->pywrap_module);
 
198
 
 
199
        // Crashes Python2
 
200
//    if (ctx->py->main_module) Py_DECREF(ctx->py->main_module);
 
201
 
 
202
    PyGILState_Release(gstate);
 
203
}
 
204
 
 
205
 
129
206
# if PY_MAJOR_VERSION >= 3
130
207
/**
131
208
 * Python3 specially treats the main thread intializing Python. It crashes if
146
223
 * http://stackoverflow.com/questions/15470367/pyeval-initthreads-in-python-3-how-when-to-call-it-the-saga-continues-ad-naus
147
224
 */
148
225
static void *pcilib_py_run_init_thread(void *arg) {
149
 
    pcilib_py_t *py = (pcilib_py_t*)(arg);
 
226
    PyThreadState *state;
 
227
    pcilib_t *ctx = (pcilib_t*)arg;
 
228
    pcilib_py_t *py = ctx->py;
150
229
 
151
230
    Py_Initialize();
 
231
 
152
232
    PyEval_InitThreads();
153
 
    PyEval_ReleaseLock();
 
233
 
 
234
//    state = PyThreadState_Get();
 
235
//    py->istate = state->interp;
 
236
 
 
237
    py->status = pcilib_py_load_default_modules(ctx);
 
238
 
 
239
    state = PyEval_SaveThread();
154
240
 
155
241
        // Ensure that main thread waiting for our signal
156
242
    pthread_mutex_lock(&(py->lock));
157
 
   
 
243
 
158
244
        // Inform the parent thread that initialization is finished
159
245
    pthread_cond_signal(&(py->cond));
160
246
 
161
247
        // Wait untill cleanup is requested
162
248
    pthread_cond_wait(&(py->cond), &(py->lock));
163
249
    pthread_mutex_unlock(&(py->lock));
164
 
    
 
250
 
 
251
    PyEval_RestoreThread(state);
 
252
    pcilib_py_clean_default_modules(ctx);
165
253
    Py_Finalize();
166
 
    
 
254
 
167
255
    return NULL;
168
256
}
169
257
# endif /* PY_MAJOR_VERSION < 3 */
171
259
 
172
260
int pcilib_init_py(pcilib_t *ctx) {
173
261
#ifdef HAVE_PYTHON
 
262
    int err = 0;
 
263
 
174
264
    ctx->py = (pcilib_py_t*)malloc(sizeof(pcilib_py_t));
175
265
    if (!ctx->py) return PCILIB_ERROR_MEMORY;
176
266
    memset(ctx->py, 0, sizeof(pcilib_py_t));
181
271
            // Since python is being initializing from c programm, it needs to initialize threads to work properly with c threads
182
272
        PyEval_InitThreads();
183
273
        PyEval_ReleaseLock();
 
274
 
 
275
        err = pcilib_py_load_default_modules(ctx);
184
276
# else /* PY_MAJOR_VERSION < 3 */
185
277
        int err = pthread_mutex_init(&(ctx->py->lock), NULL);
186
278
        if (err) return PCILIB_ERROR_FAILED;
199
291
        }
200
292
 
201
293
            // Create initalizer thread and wait until it releases the Lock
202
 
        err = pthread_create(&(ctx->py->pth), NULL, pcilib_py_run_init_thread, ctx->py);
 
294
        err = pthread_create(&(ctx->py->pth), NULL, pcilib_py_run_init_thread, (void*)ctx);
203
295
        if (err) {
204
296
            pthread_mutex_unlock(&(ctx->py->lock));
205
297
            pthread_cond_destroy(&(ctx->py->cond));
209
301
 
210
302
            // Wait until initialized and keep the lock afterwards until free executed
211
303
        pthread_cond_wait(&(ctx->py->cond), &(ctx->py->lock));
 
304
        err = ctx->py->status;
 
305
 
 
306
//      ctx->py->tstate =  PyThreadState_New(ctx->py->istate);
212
307
# endif /* PY_MAJOR_VERSION < 3 */
213
308
        ctx->py->finalyze = 1;
214
 
    }
215
 
 
216
 
        
217
 
    PyGILState_STATE gstate = PyGILState_Ensure();
218
 
 
219
 
    ctx->py->main_module = PyImport_AddModule("__parser__");
220
 
    if (!ctx->py->main_module) {
221
 
        PyGILState_Release(gstate);
222
 
        pcilib_python_warning("Error importing python parser");
223
 
        return PCILIB_ERROR_FAILED;
224
 
    }
225
 
 
226
 
    ctx->py->global_dict = PyModule_GetDict(ctx->py->main_module);
227
 
    if (!ctx->py->global_dict) {
228
 
        PyGILState_Release(gstate);
229
 
        pcilib_python_warning("Error locating global python dictionary");
230
 
        return PCILIB_ERROR_FAILED;
231
 
    }
232
 
 
233
 
    PyObject *pywrap = PyImport_ImportModule(PCILIB_PYTHON_WRAPPER);
234
 
    if (!pywrap) {
235
 
        PyGILState_Release(gstate);
236
 
        pcilib_python_warning("Error importing pcilib python wrapper");
237
 
        return PCILIB_ERROR_FAILED;
238
 
    }
239
 
        
240
 
    PyObject *mod_name = PyUnicode_FromString(PCILIB_PYTHON_WRAPPER);
241
 
    PyObject *pyctx = PyCapsule_New(ctx, "pcilib", NULL);
242
 
    ctx->py->pcilib_pywrap = PyObject_CallMethodObjArgs(pywrap, mod_name, pyctx, NULL);
243
 
    Py_XDECREF(pyctx);
244
 
    Py_XDECREF(mod_name);
245
 
        
246
 
    if (!ctx->py->pcilib_pywrap) {
247
 
        PyGILState_Release(gstate);
248
 
        pcilib_python_warning("Error initializing python wrapper");
249
 
        return PCILIB_ERROR_FAILED;
250
 
    }
251
 
    
252
 
    PyGILState_Release(gstate);
 
309
    } else {
 
310
        err = pcilib_py_load_default_modules(ctx);
 
311
    }
 
312
 
 
313
    if (err) {
 
314
        pcilib_free_py(ctx);
 
315
        return err;
 
316
    }
253
317
#endif /* HAVE_PYTHON */
254
318
 
255
319
    return 0;
256
320
}
257
321
 
 
322
void pcilib_free_py(pcilib_t *ctx) {
 
323
#ifdef HAVE_PYTHON
 
324
    if (ctx->py) {
 
325
        PyGILState_STATE gstate;
 
326
 
 
327
        gstate = PyGILState_Ensure();
 
328
        if (ctx->py->script_hash) {
 
329
            pcilib_script_t *script, *script_tmp;
 
330
 
 
331
            HASH_ITER(hh, ctx->py->script_hash, script, script_tmp) {
 
332
                Py_DECREF(script->module);
 
333
                HASH_DEL(ctx->py->script_hash, script);
 
334
                free(script);
 
335
            }
 
336
            ctx->py->script_hash = NULL;
 
337
        }
 
338
        PyGILState_Release(gstate);
 
339
 
 
340
#if PY_MAJOR_VERSION < 3
 
341
        pcilib_py_clean_default_modules(ctx);
 
342
#endif /* PY_MAJOR_VERSION < 3 */
 
343
 
 
344
        if (ctx->py->finalyze) {
 
345
#if PY_MAJOR_VERSION < 3
 
346
            Py_Finalize();
 
347
#else /* PY_MAJOR_VERSION < 3 */
 
348
//          PyThreadState_Delete(ctx->py->tstate);
 
349
 
 
350
                // singal python init thread to stop and wait it to finish
 
351
            pthread_cond_signal(&(ctx->py->cond));
 
352
            pthread_mutex_unlock(&(ctx->py->lock));
 
353
            pthread_join(ctx->py->pth, NULL);
 
354
 
 
355
                // destroy synchronization primitives
 
356
            pthread_cond_destroy(&(ctx->py->cond));
 
357
            pthread_mutex_destroy(&(ctx->py->lock));
 
358
#endif /* PY_MAJOR_VERSION < 3 */
 
359
        }
 
360
        free(ctx->py);
 
361
        ctx->py = NULL;
 
362
    }
 
363
#endif /* HAVE_PYTHON */
 
364
}
 
365
 
258
366
int pcilib_py_add_script_dir(pcilib_t *ctx, const char *dir) {
259
367
#ifdef HAVE_PYTHON
260
368
    int err = 0;
276
384
        if (!script_dir) return PCILIB_ERROR_MEMORY;
277
385
        sprintf(script_dir, "%s/%s", model_dir, dir);
278
386
    }
279
 
    
 
387
 
280
388
    PyGILState_STATE gstate = PyGILState_Ensure();
281
389
 
282
390
    pypath = PySys_GetObject("path");
292
400
        pcilib_python_warning("Can't create python string");
293
401
        return PCILIB_ERROR_MEMORY;
294
402
    }
295
 
    
 
403
 
296
404
    // Checking if the directory already in the path?
297
405
    pydict = PyDict_New();
298
406
    if (pydict) {
329
437
    return 0;
330
438
}
331
439
 
332
 
void pcilib_free_py(pcilib_t *ctx) {
333
 
#ifdef HAVE_PYTHON
334
 
    int finalyze = 0;
335
 
    
336
 
    if (ctx->py) {              
337
 
        PyGILState_STATE gstate;
338
 
 
339
 
        if (ctx->py->finalyze) finalyze = 1;
340
 
        
341
 
        gstate = PyGILState_Ensure();
342
 
 
343
 
        if (ctx->py->script_hash) {
344
 
            pcilib_script_t *script, *script_tmp;
345
 
 
346
 
            HASH_ITER(hh, ctx->py->script_hash, script, script_tmp) {
347
 
                Py_DECREF(script->module);
348
 
                HASH_DEL(ctx->py->script_hash, script);
349
 
                free(script);
350
 
            }
351
 
            ctx->py->script_hash = NULL;
352
 
        }
353
 
 
354
 
        if (ctx->py->pcilib_pywrap)
355
 
            Py_DECREF(ctx->py->pcilib_pywrap);
356
 
 
357
 
        PyGILState_Release(gstate);
358
 
    
359
 
        
360
 
        free(ctx->py);
361
 
        ctx->py = NULL;
362
 
    }
363
 
    
364
 
    
365
 
    if (finalyze) {
366
 
#if PY_MAJOR_VERSION < 3
367
 
       Py_Finalize();
368
 
#else /* PY_MAJOR_VERSION < 3 */
369
 
          // singal python init thread to stop and wait it to finish
370
 
       pthread_cond_signal(&(ctx->py->cond));
371
 
       pthread_mutex_unlock(&(ctx->py->lock));
372
 
       pthread_join(ctx->py->pth, NULL);
373
 
  
374
 
          // destroy synchronization primitives
375
 
       pthread_cond_destroy(&(ctx->py->cond));
376
 
       pthread_mutex_destroy(&(ctx->py->lock));
377
 
#endif /* PY_MAJOR_VERSION < 3 */
378
 
    }
379
 
#endif /* HAVE_PYTHON */
380
 
}
381
440
 
382
441
int pcilib_py_load_script(pcilib_t *ctx, const char *script_name) {
383
442
#ifdef HAVE_PYTHON
407
466
        pcilib_python_error("Error importing script (%s)", script_name);
408
467
        return PCILIB_ERROR_FAILED;
409
468
    }
410
 
    PyGILState_Release(gstate);
411
469
 
412
470
    module = (pcilib_script_t*)malloc(sizeof(pcilib_script_t));
413
 
    if (!module) return PCILIB_ERROR_MEMORY;
 
471
    if (!module) {
 
472
        Py_DECREF(pymodule);
 
473
        PyGILState_Release(gstate);
 
474
        return PCILIB_ERROR_MEMORY;
 
475
    }
 
476
 
 
477
    PyGILState_Release(gstate);
414
478
 
415
479
    module->module = pymodule;
416
480
    module->name = script_name;
464
528
    PyGILState_Release(gstate);
465
529
#endif /* HAVE_PYTHON */
466
530
 
 
531
//    pcilib_py_load_default_modules(py->ctx);
 
532
 
467
533
    if (mode_ret) *mode_ret = mode;
468
534
    return 0;
469
535
}