/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-02-23 06:20:33 UTC
  • mfrom: (346.1.18 pcitool)
  • Revision ID: csa@suren.me-20160223062033-mz8qkpm1a2oioveb
Merge Python scripting support from Vasiliy Chernov

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#include <Python.h>
2
 
 
 
1
#define _GNU_SOURCE
3
2
#include <stdio.h>
4
3
#include <stdlib.h>
5
4
#include <string.h>
6
5
#include <strings.h>
7
 
 
 
6
#include <alloca.h>
8
7
 
9
8
#include "pci.h"
10
9
#include "debug.h"
11
10
#include "pcilib.h"
12
11
#include "py.h"
13
12
#include "error.h"
 
13
#include "config.h"
 
14
 
 
15
#ifdef HAVE_PYTHON
 
16
# include <Python.h>
 
17
#endif /* HAVE_PYTHON */
 
18
 
 
19
#ifdef HAVE_PYTHON
 
20
typedef struct pcilib_script_s pcilib_script_t;
 
21
 
 
22
struct pcilib_script_s {
 
23
    const char *name;                   /**< Script name */
 
24
    PyObject *module;                   /**< PyModule object, contains script enviroment */     
 
25
    UT_hash_handle hh;                  /**< hash */
 
26
};
14
27
 
15
28
struct pcilib_py_s {
16
 
    PyObject *main_module;
17
 
    PyObject *global_dict;
 
29
    int finalyze;                       /**< Indicates, that we are initialized from wrapper and should not destroy Python resources in destructor */
 
30
    PyObject *main_module;              /**< Main interpreter */
 
31
    PyObject *global_dict;              /**< Dictionary of main interpreter */
 
32
    PyObject *pcilib_pywrap;            /**< pcilib wrapper module */
 
33
    pcilib_script_t *script_hash;       /**< Hash with loaded scripts */
18
34
};
 
35
#endif /* HAVE_PYTHON */
 
36
 
 
37
void pcilib_log_python_error(const char *file, int line, pcilib_log_flags_t flags, pcilib_log_priority_t prio, const char *msg, ...) {
 
38
    va_list va;
 
39
    const char *type = NULL;
 
40
    const char *val = NULL;
 
41
 
 
42
#ifdef HAVE_PYTHON
 
43
    PyObject *pytype = NULL;
 
44
    PyObject *pyval = NULL;
 
45
    PyObject *pytraceback = NULL;
 
46
 
 
47
    PyErr_Fetch(&pytype, &pyval, &pytraceback);
 
48
    type = PyString_AsString(pytype);
 
49
    val = PyString_AsString(pyval);
 
50
#endif /* HAVE_PYTHON */
 
51
    
 
52
    va_start(va, msg);
 
53
    if (type) {
 
54
        char *str;
 
55
        size_t len = 32;
 
56
 
 
57
        if (msg) len += strlen(msg);
 
58
        if (type) len += strlen(type);
 
59
        if (val) len += strlen(val);
 
60
            
 
61
        str = alloca(len * sizeof(char));
 
62
        if (str) {
 
63
            if (msg&&val)
 
64
                sprintf(str, "%s <%s: %s>", msg, type, val);
 
65
            else if (msg)
 
66
                sprintf(str, "%s <%s>", msg, type);
 
67
            else if (val)
 
68
                sprintf(str, "Python error %s: %s", type, val);
 
69
            else
 
70
                sprintf(str, "Python error %s", type);
 
71
            
 
72
            pcilib_log_vmessage(file, line, flags, prio, str, va);
 
73
        }
 
74
    } else  {
 
75
        pcilib_log_vmessage(file, line, flags, prio, msg, va);
 
76
    }
 
77
    va_end(va);
 
78
 
 
79
#ifdef HAVE_PYTHON
 
80
    Py_XDECREF(pytype);
 
81
    Py_XDECREF(pyval);
 
82
    Py_XDECREF(pytraceback);
 
83
#endif /* HAVE_PYTHON */
 
84
}
 
85
 
 
86
 
19
87
 
20
88
int pcilib_init_py(pcilib_t *ctx) {
 
89
#ifdef HAVE_PYTHON
21
90
    ctx->py = (pcilib_py_t*)malloc(sizeof(pcilib_py_t));
22
91
    if (!ctx->py) return PCILIB_ERROR_MEMORY;
23
92
 
24
 
    Py_Initialize();
 
93
    memset(ctx->py, 0, sizeof(pcilib_py_t));
25
94
 
 
95
    if(Py_IsInitialized())
 
96
        ctx->py->finalyze = 1;
 
97
    else {
 
98
        Py_Initialize();
 
99
        
 
100
            // Since python is being initializing from c programm, it needs to initialize threads to work properly with c threads
 
101
        PyEval_InitThreads();
 
102
        PyEval_ReleaseLock();
 
103
    }
 
104
                
26
105
    ctx->py->main_module = PyImport_AddModule("__parser__");
27
 
    if (!ctx->py->main_module)
 
106
    if (!ctx->py->main_module) {
 
107
        pcilib_python_error("Error importing python parser");
28
108
        return PCILIB_ERROR_FAILED;
 
109
    }
29
110
 
30
111
    ctx->py->global_dict = PyModule_GetDict(ctx->py->main_module);
31
 
    if (!ctx->py->global_dict)
32
 
        return PCILIB_ERROR_FAILED;
 
112
    if (!ctx->py->global_dict) {
 
113
        pcilib_python_error("Error locating global python dictionary");
 
114
        return PCILIB_ERROR_FAILED;
 
115
    }
 
116
 
 
117
    PyObject *pywrap = PyImport_ImportModule("pcipywrap");
 
118
    if (!pywrap) {
 
119
        pcilib_python_error("Error importing pcilib python wrapper");
 
120
        return PCILIB_ERROR_FAILED;
 
121
    }
 
122
        
 
123
    PyObject *mod_name = PyString_FromString("Pcipywrap");
 
124
    ctx->py->pcilib_pywrap = PyObject_CallMethodObjArgs(pywrap, mod_name, PyCObject_FromVoidPtr(ctx, NULL), NULL);
 
125
    Py_XDECREF(mod_name);
 
126
        
 
127
    if (!ctx->py->pcilib_pywrap) {
 
128
        pcilib_python_error("Error initializing python wrapper");
 
129
        return PCILIB_ERROR_FAILED;
 
130
    }
 
131
#endif /* HAVE_PYTHON */
 
132
 
 
133
    return 0;
 
134
}
 
135
 
 
136
int pcilib_py_add_script_dir(pcilib_t *ctx, const char *dir) {
 
137
#ifdef HAVE_PYTHON
 
138
    PyObject* pypath;
 
139
    char *script_dir;
 
140
 
 
141
    const char *model_dir = getenv("PCILIB_MODEL_DIR");
 
142
    if (!model_dir) model_dir = PCILIB_MODEL_DIR;
 
143
 
 
144
    if (!dir) dir = ctx->model;
 
145
 
 
146
    if (*dir == '/') {
 
147
        script_dir = (char*)dir;
 
148
    } else {
 
149
        script_dir = alloca(strlen(model_dir) + strlen(dir) + 2);
 
150
        if (!script_dir) return PCILIB_ERROR_MEMORY;
 
151
        sprintf(script_dir, "%s/%s", model_dir, dir);
 
152
    }
 
153
 
 
154
    pypath = PySys_GetObject("path");
 
155
    if (!pypath) {
 
156
        pcilib_python_error("Can't get python path");
 
157
        return PCILIB_ERROR_FAILED;
 
158
    }
 
159
 
 
160
        // Shall we check if the directory already in the path?
 
161
    if(PyList_Append(pypath, PyString_FromString(script_dir)) == -1) {
 
162
        pcilib_python_error("Can't add directory (%s) to python path", script_dir);
 
163
        return PCILIB_ERROR_FAILED;
 
164
    }
 
165
#endif /* HAVE_PYTHON */
33
166
 
34
167
    return 0;
35
168
}
36
169
 
37
170
void pcilib_free_py(pcilib_t *ctx) {
38
 
    if (ctx->py) {
39
 
            // Dict and module references are borrowed
 
171
#ifdef HAVE_PYTHON
 
172
    int finalyze = 0;
 
173
        
 
174
    if (ctx->py) {              
 
175
        if(ctx->py->finalyze) finalyze = 1;
 
176
 
 
177
        if (ctx->py->script_hash) {
 
178
            pcilib_script_t *script, *script_tmp;
 
179
 
 
180
            HASH_ITER(hh, ctx->py->script_hash, script, script_tmp) {
 
181
                HASH_DEL(ctx->py->script_hash, script);
 
182
                free(script);
 
183
            }
 
184
            ctx->py->script_hash = NULL;
 
185
        }
 
186
 
40
187
        free(ctx->py);
41
188
        ctx->py = NULL;
42
189
    }
43
 
 
44
 
    Py_Finalize();
45
 
}
46
 
 
47
 
/*
48
 
static int pcilib_py_realloc_string(pcilib_t *ctx, size_t required, size_t *size, char **str) {
49
 
    char *ptr;
50
 
    size_t cur = *size;
51
 
    
52
 
    if ((required + 1) > cur) {
53
 
        while (cur < required) cur *= 2;
54
 
        ptr = (char*)realloc(*str, cur);
55
 
        if (!ptr) return PCILIB_ERROR_MEMORY;
56
 
        *size = cur;
57
 
        *str = ptr;
58
 
    }
59
 
    ]
60
 
    return 0;
61
 
}
62
 
*/
63
 
 
 
190
    
 
191
    if (finalyze)
 
192
        Py_Finalize();
 
193
#endif /* HAVE_PYTHON */
 
194
}
 
195
 
 
196
int pcilib_py_load_script(pcilib_t *ctx, const char *script_name) {
 
197
#ifdef HAVE_PYTHON
 
198
    PyObject* pymodule;
 
199
    pcilib_script_t *module = NULL;
 
200
 
 
201
 
 
202
    char *module_name = strdupa(script_name);
 
203
    if (!module_name) return PCILIB_ERROR_MEMORY;
 
204
 
 
205
    char *py = strrchr(module_name, '.');
 
206
    if ((!py)||(strcasecmp(py, ".py"))) {
 
207
        pcilib_error("Invalid script name (%s) is specified", script_name);
 
208
        return PCILIB_ERROR_INVALID_ARGUMENT;
 
209
    }
 
210
    *py = 0;
 
211
 
 
212
    HASH_FIND_STR(ctx->py->script_hash, script_name, module);
 
213
    if (module) return 0;
 
214
 
 
215
    pymodule = PyImport_ImportModule(module_name);
 
216
    if (!pymodule) {
 
217
        pcilib_python_error("Error importing script (%s)", script_name);
 
218
        return PCILIB_ERROR_FAILED;
 
219
    }
 
220
 
 
221
    module = (pcilib_script_t*)malloc(sizeof(pcilib_script_t));
 
222
    if (!module) return PCILIB_ERROR_MEMORY;
 
223
 
 
224
    module->module = pymodule;
 
225
    module->name = script_name;
 
226
    HASH_ADD_KEYPTR(hh, ctx->py->script_hash, module->name, strlen(module->name), module);
 
227
#endif /* HAVE_PYTHON */
 
228
    return 0;
 
229
}
 
230
 
 
231
int pcilib_py_get_transform_script_properties(pcilib_t *ctx, const char *script_name, pcilib_access_mode_t *mode_ret) {
 
232
    pcilib_access_mode_t mode = 0;
 
233
 
 
234
#ifdef HAVE_PYTHON
 
235
    PyObject *dict;
 
236
    PyObject *pystr;
 
237
    pcilib_script_t *module;
 
238
        
 
239
    HASH_FIND_STR(ctx->py->script_hash, script_name, module);
 
240
 
 
241
    if(!module) {
 
242
        pcilib_error("Script (%s) is not loaded yet", script_name);
 
243
        return PCILIB_ERROR_NOTFOUND;
 
244
    }
 
245
        
 
246
    dict = PyModule_GetDict(module->module);
 
247
    if (!dict) {
 
248
        pcilib_python_error("Error getting dictionary for script (%s)", script_name);
 
249
        return PCILIB_ERROR_FAILED;
 
250
    }
 
251
    
 
252
    pystr = PyString_FromString("read_from_register");
 
253
    if (pystr) {
 
254
        if (PyDict_Contains(dict, pystr)) mode |= PCILIB_ACCESS_R;
 
255
        Py_XDECREF(pystr);
 
256
    }
 
257
 
 
258
    pystr = PyString_FromString("write_to_register");
 
259
    if (pystr) {
 
260
        if (PyDict_Contains(dict, pystr)) mode |= PCILIB_ACCESS_W;
 
261
        Py_XDECREF(pystr);
 
262
    }
 
263
#endif /* HAVE_PYTHON */
 
264
 
 
265
    if (mode_ret) *mode_ret = mode;
 
266
    return 0;
 
267
}
 
268
 
 
269
pcilib_py_object *pcilib_get_value_as_pyobject(pcilib_t* ctx, pcilib_value_t *val, int *ret) {
 
270
#ifdef HAVE_PYTHON      
 
271
    int err = 0;
 
272
    PyObject *res = NULL;
 
273
 
 
274
    long ival;
 
275
    double fval;
 
276
        
 
277
    switch(val->type) {
 
278
     case PCILIB_TYPE_LONG:
 
279
        ival = pcilib_get_value_as_int(ctx, val, &err);
 
280
        if (!err) res = (PyObject*)PyInt_FromLong(ival);
 
281
        break;
 
282
     case PCILIB_TYPE_DOUBLE:
 
283
        fval = pcilib_get_value_as_float(ctx, val, &err);
 
284
        if (!err) res = (PyObject*)PyFloat_FromDouble(fval);
 
285
        break;  
 
286
     default:
 
287
        err = PCILIB_ERROR_NOTSUPPORTED;
 
288
        pcilib_error("Can't convert pcilib value of type (%lu) to PyObject", val->type);
 
289
    }
 
290
 
 
291
    if (err) {
 
292
        if (ret) *ret = err;
 
293
        return NULL;
 
294
    } else if (!res) {
 
295
        if (ret) *ret = PCILIB_ERROR_MEMORY;
 
296
        return res;
 
297
    } 
 
298
 
 
299
    if (ret) *ret = 0;
 
300
    return res;
 
301
#else /* HAVE_PYTHON */
 
302
    pcilib_error("Python is not supported");
 
303
    return NULL;
 
304
#endif /* HAVE_PYTHON */
 
305
}
 
306
 
 
307
int pcilib_set_value_from_pyobject(pcilib_t* ctx, pcilib_value_t *val, pcilib_py_object *pval) {
 
308
#ifdef HAVE_PYTHON
 
309
    int err = 0;
 
310
    PyObject *pyval = (PyObject*)pval;
 
311
        
 
312
    if (PyInt_Check(pyval)) {
 
313
        err = pcilib_set_value_from_int(ctx, val, PyInt_AsLong(pyval));
 
314
    } else if (PyFloat_Check(pyval)) {
 
315
        err = pcilib_set_value_from_float(ctx, val, PyFloat_AsDouble(pyval));
 
316
    } else if (PyString_Check(pyval)) {
 
317
        err = pcilib_set_value_from_string(ctx, val, PyString_AsString(pyval));
 
318
    } else {
 
319
        pcilib_error("Can't convert PyObject to polymorphic pcilib value");
 
320
        err = PCILIB_ERROR_NOTSUPPORTED;
 
321
    }
 
322
    
 
323
    return err;
 
324
#else /* HAVE_PYTHON */
 
325
    pcilib_error("Python is not supported");
 
326
    return PCILIB_ERROR_NOTSUPPORTED;
 
327
#endif /* HAVE_PYTHON */
 
328
}
 
329
 
 
330
#ifdef HAVE_PYTHON
64
331
static char *pcilib_py_parse_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *value) {
65
332
    int i;
66
333
    int err = 0;
166
433
 
167
434
    return dst;
168
435
}
 
436
#endif /* HAVE_PYTHON */
169
437
 
170
438
int pcilib_py_eval_string(pcilib_t *ctx, const char *codestr, pcilib_value_t *value) {
 
439
#ifdef HAVE_PYTHON
171
440
    PyGILState_STATE gstate;
172
441
    char *code;
173
442
    PyObject* obj;
189
458
 
190
459
    pcilib_debug(VIEWS, "Evaluating a Python string \'%s\' to %lf=\'%s\'", codestr, PyFloat_AsDouble(obj), code);
191
460
    return pcilib_set_value_from_float(ctx, value, PyFloat_AsDouble(obj));
 
461
#else /* HAVE_PYTHON */
 
462
        pcilib_error("Current build not support python.");
 
463
    return PCILIB_ERROR_NOTAVAILABLE;
 
464
#endif /* HAVE_PYTHON */
 
465
}
 
466
 
 
467
int pcilib_py_eval_func(pcilib_t *ctx, const char *script_name, const char *func_name, pcilib_value_t *val) {
 
468
#ifdef HAVE_PYTHON
 
469
    int err = 0;
 
470
    PyObject *pyfunc;
 
471
    PyObject *pyval = NULL, *pyret;
 
472
    pcilib_script_t *module = NULL;
 
473
 
 
474
    HASH_FIND_STR(ctx->py->script_hash, script_name, module);
 
475
 
 
476
    if (!module) {
 
477
        pcilib_error("Script (%s) is not loaded", script_name);
 
478
        return PCILIB_ERROR_NOTFOUND;
 
479
    }
 
480
 
 
481
    if (val) {
 
482
        pyval = pcilib_get_value_as_pyobject(ctx, val, &err);
 
483
        if (err) return err;
 
484
    }
 
485
 
 
486
    pyfunc = PyUnicode_FromString(func_name);
 
487
    if (!pyfunc) {
 
488
        if (pyval) Py_XDECREF(pyval);
 
489
        return PCILIB_ERROR_MEMORY;
 
490
    }
 
491
 
 
492
    PyGILState_STATE gstate = PyGILState_Ensure();
 
493
    pyret = PyObject_CallMethodObjArgs(module->module, pyfunc, ctx->py->pcilib_pywrap, pyval, NULL);
 
494
    PyGILState_Release(gstate);
 
495
 
 
496
    Py_XDECREF(pyfunc);
 
497
    Py_XDECREF(pyval);
 
498
        
 
499
    if (!pyret) {
 
500
        pcilib_python_error("Error executing function (%s) of python script (%s)", func_name, script_name);
 
501
        return PCILIB_ERROR_FAILED;
 
502
    }
 
503
 
 
504
    if ((val)&&(pyret != Py_None))
 
505
        err = pcilib_set_value_from_pyobject(ctx, val, pyret);
 
506
 
 
507
    Py_XDECREF(pyret);
 
508
 
 
509
    return err;
 
510
#else /* HAVE_PYTHON */
 
511
    pcilib_error("Python is not supported");
 
512
    return PCILIB_ERROR_NOTSUPPORTED;
 
513
#endif /* HAVE_PYTHON */
192
514
}