/alps/pcitool

To get this branch, use:
bzr branch http://darksoft.org/webbzr/alps/pcitool

« back to all changes in this revision

Viewing changes to pcilib/py.c

  • Committer: Suren A. Chilingaryan
  • Date: 2016-03-04 18:30:43 UTC
  • mfrom: (346.1.39 pcitool)
  • Revision ID: csa@suren.me-20160304183043-mjf6xvyermjh5olg
Integrate last part of Python code from Vasiliy Chernov

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
 
3
3
#ifdef HAVE_PYTHON
4
4
# include <Python.h>
 
5
 
 
6
# if PY_MAJOR_VERSION >= 3
 
7
#  include <pthread.h>
 
8
# endif /* PY_MAJOR_VERSION >= 3 */
5
9
#endif /* HAVE_PYTHON */
6
10
 
7
11
#include <stdio.h>
17
21
#include "error.h"
18
22
 
19
23
#ifdef HAVE_PYTHON
20
 
#define PCILIB_PYTHON_WRAPPER "pcipywrap"
 
24
# define PCILIB_PYTHON_WRAPPER "pcipywrap"
21
25
 
22
26
typedef struct pcilib_script_s pcilib_script_t;
23
27
 
33
37
    PyObject *global_dict;              /**< Dictionary of main interpreter */
34
38
    PyObject *pcilib_pywrap;            /**< pcilib wrapper module */
35
39
    pcilib_script_t *script_hash;       /**< Hash with loaded scripts */
 
40
    
 
41
# if PY_MAJOR_VERSION >= 3
 
42
    pthread_t pth;
 
43
    pthread_cond_t cond;
 
44
    pthread_mutex_t lock;
 
45
# endif /* PY_MAJOR_VERSION > 3 */
36
46
};
37
47
#endif /* HAVE_PYTHON */
38
48
 
115
125
#endif /* HAVE_PYTHON */
116
126
}
117
127
 
118
 
 
 
128
#ifdef HAVE_PYTHON
 
129
# if PY_MAJOR_VERSION >= 3
 
130
/**
 
131
 * Python3 specially treats the main thread intializing Python. It crashes if
 
132
 * the Lock is released and any Python code is executed under the GIL compaling
 
133
 * that GIL is not locked. Python3 assumes that the main thread most of the time
 
134
 * holds the Lock, only shortly giving it away to other threads and re-obtaining 
 
135
 * it hereafter. This is not possible to do with GILs, but instead (probably)
 
136
 * PyEval_{Save,Restore}Thread() should be used. On other hand, the other threads
 
137
 * are working fine with GILs. This makes things complicated as we need to know
 
138
 * if we are running in main thread or not.
 
139
 * To simplify matters, during initalization we start a new thread which will
 
140
 * performa actual initialization of Python and, hence, act as main thread.
 
141
 * We only intialize here. No python code is executed afterwards. So we don't
 
142
 * need to care about special locking mechanisms in main thread. Instead all
 
143
 * our user threads can use GILs normally. 
 
144
 * See more details here:
 
145
 * http://stackoverflow.com/questions/24499393/cpython-locking-the-gil-in-the-main-thread
 
146
 * http://stackoverflow.com/questions/15470367/pyeval-initthreads-in-python-3-how-when-to-call-it-the-saga-continues-ad-naus
 
147
 */
 
148
static void *pcilib_py_run_init_thread(void *arg) {
 
149
    pcilib_py_t *py = (pcilib_py_t*)(arg);
 
150
 
 
151
    Py_Initialize();
 
152
    PyEval_InitThreads();
 
153
    PyEval_ReleaseLock();
 
154
 
 
155
        // Ensure that main thread waiting for our signal
 
156
    pthread_lock(&(py->lock));
 
157
   
 
158
        // Inform the parent thread that initialization is finished
 
159
    pthread_cond_signal(&(py->cond));
 
160
 
 
161
        // Wait untill cleanup is requested
 
162
    pthread_cond_wait(&(py->cond), &(py->lock));
 
163
    pthread_unlock(&(py->lock)));
 
164
    
 
165
    Py_Finalize();
 
166
    
 
167
    return NULL;
 
168
}
 
169
# endif /* PY_MAJOR_VERSION < 3 */
 
170
#endif /* HAVE_PYTHON */
119
171
 
120
172
int pcilib_init_py(pcilib_t *ctx) {
121
173
#ifdef HAVE_PYTHON
122
174
    ctx->py = (pcilib_py_t*)malloc(sizeof(pcilib_py_t));
123
175
    if (!ctx->py) return PCILIB_ERROR_MEMORY;
124
 
 
125
176
    memset(ctx->py, 0, sizeof(pcilib_py_t));
126
177
 
127
 
    if(!Py_IsInitialized()) {
 
178
    if (!Py_IsInitialized()) {
 
179
# if PY_MAJOR_VERSION < 3
128
180
        Py_Initialize();
129
 
        
130
181
            // Since python is being initializing from c programm, it needs to initialize threads to work properly with c threads
131
182
        PyEval_InitThreads();
132
183
        PyEval_ReleaseLock();
 
184
# else /* PY_MAJOR_VERSION < 3 */
 
185
        err = pthread_mutex_init(&(ctx->py.lock));
 
186
        if (err) return PCILIB_ERROR_FAILED;
 
187
 
 
188
        err = pthread_cond_init(&(ctx->py.cond));
 
189
        if (err) {
 
190
            pthread_mutex_destroy(&(ctx->py.lock));
 
191
            return PCILIB_ERROR_FAILED;
 
192
        }
 
193
 
 
194
        err = pthread_mutex_lock(&(ctx->py.lock));
 
195
        if (err) {
 
196
            pthread_cond_destroy(&(ctx->py.lock));
 
197
            pthread_mutex_destroy(&(ctx->py.lock));
 
198
            return PCILIB_ERROR_FAILED;
 
199
        }
 
200
 
 
201
            // 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));
 
203
        if (err) {
 
204
            pthread_mutex_unlock(&(ctx->py.lock));
 
205
            pthread_cond_destroy(&(ctx->py.cond));
 
206
            pthread_mutex_destroy(&(ctx->py.lock));
 
207
            return PCILIB_ERROR_FAILED;
 
208
        }
 
209
 
 
210
            // Wait until initialized and keep the lock afterwards until free executed
 
211
        pthread_cond_wait(&(ctx->py.cond), (ctx->py.lock));
 
212
# endif /* PY_MAJOR_VERSION < 3 */
133
213
        ctx->py->finalyze = 1;
134
214
    }
135
 
                
 
215
 
 
216
        
 
217
    PyGILState_STATE gstate = PyGILState_Ensure();
 
218
 
136
219
    ctx->py->main_module = PyImport_AddModule("__parser__");
137
220
    if (!ctx->py->main_module) {
 
221
        PyGILState_Release(gstate);
138
222
        pcilib_python_warning("Error importing python parser");
139
223
        return PCILIB_ERROR_FAILED;
140
224
    }
141
225
 
142
226
    ctx->py->global_dict = PyModule_GetDict(ctx->py->main_module);
143
227
    if (!ctx->py->global_dict) {
 
228
        PyGILState_Release(gstate);
144
229
        pcilib_python_warning("Error locating global python dictionary");
145
230
        return PCILIB_ERROR_FAILED;
146
231
    }
147
232
 
148
233
    PyObject *pywrap = PyImport_ImportModule(PCILIB_PYTHON_WRAPPER);
149
234
    if (!pywrap) {
 
235
        PyGILState_Release(gstate);
150
236
        pcilib_python_warning("Error importing pcilib python wrapper");
151
237
        return PCILIB_ERROR_FAILED;
152
238
    }
158
244
    Py_XDECREF(mod_name);
159
245
        
160
246
    if (!ctx->py->pcilib_pywrap) {
 
247
        PyGILState_Release(gstate);
161
248
        pcilib_python_warning("Error initializing python wrapper");
162
249
        return PCILIB_ERROR_FAILED;
163
250
    }
 
251
    
 
252
    PyGILState_Release(gstate);
164
253
#endif /* HAVE_PYTHON */
165
254
 
166
255
    return 0;
187
276
        if (!script_dir) return PCILIB_ERROR_MEMORY;
188
277
        sprintf(script_dir, "%s/%s", model_dir, dir);
189
278
    }
 
279
    
 
280
    PyGILState_STATE gstate = PyGILState_Ensure();
190
281
 
191
282
    pypath = PySys_GetObject("path");
192
283
    if (!pypath) {
 
284
        PyGILState_Release(gstate);
193
285
        pcilib_python_warning("Can't get python path");
194
286
        return PCILIB_ERROR_FAILED;
195
287
    }
196
288
 
197
289
    pynewdir = PyUnicode_FromString(script_dir);
198
290
    if (!pynewdir) {
 
291
        PyGILState_Release(gstate);
199
292
        pcilib_python_warning("Can't create python string");
200
293
        return PCILIB_ERROR_MEMORY;
201
294
    }
202
295
    
203
 
        // Checking if the directory already in the path?
 
296
    // Checking if the directory already in the path?
204
297
    pydict = PyDict_New();
205
298
    if (pydict) {
206
299
        pystr = PyUnicode_FromString("cur");
225
318
    if (pyret) Py_DECREF(pyret);
226
319
    Py_DECREF(pynewdir);
227
320
 
 
321
    PyGILState_Release(gstate);
 
322
 
228
323
    if (err) {
229
324
        pcilib_python_warning("Can't add directory (%s) to python path", script_dir);
230
325
        return err;
237
332
void pcilib_free_py(pcilib_t *ctx) {
238
333
#ifdef HAVE_PYTHON
239
334
    int finalyze = 0;
240
 
        
 
335
    
241
336
    if (ctx->py) {              
 
337
        PyGILState_STATE gstate;
 
338
 
242
339
        if (ctx->py->finalyze) finalyze = 1;
 
340
        
 
341
        gstate = PyGILState_Ensure();
243
342
 
244
343
        if (ctx->py->script_hash) {
245
344
            pcilib_script_t *script, *script_tmp;
254
353
 
255
354
        if (ctx->py->pcilib_pywrap)
256
355
            Py_DECREF(ctx->py->pcilib_pywrap);
 
356
 
 
357
        PyGILState_Release(gstate);
 
358
    
257
359
        
258
360
        free(ctx->py);
259
361
        ctx->py = NULL;
260
362
    }
261
363
    
262
 
    if (finalyze)
263
 
        Py_Finalize();
 
364
    
 
365
    if (finalyze) {
 
366
#if PY_MAJOR_VERSION >= 3
 
367
          // singal python init thread to stop and wait it to finish
 
368
       pthread_cond_signal(&(ctx->py.cond));
 
369
       pthread_mutex_unlock(&(ctx->py.lock));
 
370
       pthread_join(ctx->py.pth, NULL);
 
371
       
 
372
          // destroy synchronization primitives
 
373
       pthread_cond_destroy(&(ctx->py.cond));
 
374
       pthread_mutex_destroy(&(ctx->py.lock));
 
375
#else /* PY_MAJOR_VERSION < 3 */
 
376
       Py_Finalize();
 
377
#endif /* PY_MAJOR_VERSION < 3 */
 
378
    }
 
379
    
 
380
 
264
381
#endif /* HAVE_PYTHON */
265
382
}
266
383
 
268
385
#ifdef HAVE_PYTHON
269
386
    PyObject* pymodule;
270
387
    pcilib_script_t *module = NULL;
 
388
    PyGILState_STATE gstate;
271
389
 
272
390
    if (!ctx->py) return 0;
273
391
 
284
402
    HASH_FIND_STR(ctx->py->script_hash, script_name, module);
285
403
    if (module) return 0;
286
404
 
 
405
    gstate = PyGILState_Ensure();
287
406
    pymodule = PyImport_ImportModule(module_name);
288
407
    if (!pymodule) {
 
408
        PyGILState_Release(gstate);
289
409
        pcilib_python_error("Error importing script (%s)", script_name);
290
410
        return PCILIB_ERROR_FAILED;
291
411
    }
 
412
    PyGILState_Release(gstate);
292
413
 
293
414
    module = (pcilib_script_t*)malloc(sizeof(pcilib_script_t));
294
415
    if (!module) return PCILIB_ERROR_MEMORY;
307
428
    PyObject *dict;
308
429
    PyObject *pystr;
309
430
    pcilib_script_t *module;
 
431
    PyGILState_STATE gstate;
310
432
 
311
433
    if (!ctx->py) {
312
434
        if (mode_ret) *mode_ret = mode;
319
441
        pcilib_error("Script (%s) is not loaded yet", script_name);
320
442
        return PCILIB_ERROR_NOTFOUND;
321
443
    }
 
444
    
 
445
    gstate = PyGILState_Ensure();
322
446
        
323
447
    dict = PyModule_GetDict(module->module);
324
448
    if (!dict) {
 
449
        PyGILState_Release(gstate);
325
450
        pcilib_python_error("Error getting dictionary for script (%s)", script_name);
326
451
        return PCILIB_ERROR_FAILED;
327
452
    }
337
462
        if (PyDict_Contains(dict, pystr)) mode |= PCILIB_ACCESS_W;
338
463
        Py_DECREF(pystr);
339
464
    }
 
465
    
 
466
    PyGILState_Release(gstate);
340
467
#endif /* HAVE_PYTHON */
341
468
 
342
469
    if (mode_ret) *mode_ret = mode;