/* tdemo.c - threaded embed python demo */

#include <stdio.h>
#include <pthread.h>
#include "Python.h"

PyThreadState *mainThreadState;

int
InterpretPythonString(char *s)
        /* return 1 if exiting */
{
        PyObject *m, *d, *v;
        int gotnl = (NULL != strchr(s,'\n'));

        m = PyImport_AddModule("__main__");
        if (NULL == m)
                return;
        d = PyModule_GetDict(m);
        v = PyRun_String(s, gotnl ? Py_file_input : Py_single_input, d, d);
        if (NULL == v)  {
                if(PyExc_SystemExit == PyErr_Occurred()) {
                        PyErr_Clear();
                        return 1;
                }
                return 0;
        }
        Py_DECREF(v);
        return 0;
}

void  *
StartThread(void *arg)
{
        char cmd[256];
        PyThreadState *tstate;
        int loopcount = 0;

        int i = (int) arg;
        sprintf(cmd,"print 'Thread %d says hi!'\n",pthread_self());

        PyEval_AcquireLock();   /* przejmuje globalna blokade */
        tstate = PyThreadState_New(mainThreadState->interp);
        PyThreadState_Swap(tstate);     /* uzyj tego nowego stanu watku */
        while(1) {
                Py_BEGIN_ALLOW_THREADS
                sleep(i);
                Py_END_ALLOW_THREADS
                if(0 != InterpretPythonString(cmd))
                        break;
                if(2 < loopcount++)
                        strcpy(cmd,"import sys\nsys.exit(1)\n");
        }
        printf("Thread %d exiting\n",pthread_self());
        PyThreadState_Swap(NULL);       /* zeruj stan watku Pythona */
        PyThreadState_Clear(tstate);    /* wyczysc stan watku */
        PyThreadState_Delete(tstate);   /* usun stan watku */
        PyEval_ReleaseLock();
        return NULL;
}


PyObject *
LaunchThread(PyObject *a, PyObject *args)
        /* disallow all exiting */
{
        int i = 5;
        pthread_t tid;
        int rc;

        if(!PyArg_ParseTuple(args,"|i:LaunchThread",&i))
                return NULL;

        if(pthread_create(&tid,NULL,StartThread,(void *) i) < 0)
                return PyErr_SetFromErrno(PyExc_RuntimeError);

        if(pthread_detach(tid) < 0)
                return PyErr_SetFromErrno(PyExc_RuntimeError);

        return PyInt_FromLong(tid);
};

PyMethodDef host_functions[] = {
        { "LaunchThread", LaunchThread, METH_VARARGS},
        { NULL, NULL }
};

void
SetupHostModule(void)
{
        PyObject *hostmod, *sysmod;

        hostmod = Py_InitModule("hostModule",host_functions);
}

void
InitializePython(int argc, char **argv)
{
        Py_SetProgramName(argv[0]);

        PyEval_InitThreads();   /* inicjalizuj obsluge watkow, przejmij globalna blokade */

        Py_Initialize();
        PySys_SetArgv(argc, argv);
        SetupHostModule();

        mainThreadState = PyEval_SaveThread(); /* zwolnij globalna blokade */
}

int
main(int argc, char **argv)
{
        int rc;
        char cmd[1024];

        InitializePython(argc, argv);

        PyEval_AcquireLock();   /* przejmij globalna blokade interpretera */
        PyThreadState_Swap(mainThreadState);
        rc = PyRun_AnyFile(stdin,"???");
        Py_Finalize();
        /* po prostu zakoncz bez zwolnienia globalnej blokady tak, aby inne watki nie wywolywaly Pythona */
        return rc;
}
