summaryrefslogtreecommitdiffstats
path: root/Demo/pysvr/pysvr.c
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1997-07-19 21:00:47 (GMT)
committerGuido van Rossum <guido@python.org>1997-07-19 21:00:47 (GMT)
commit5c8b9911750565713cba39fd8835cc951ddf2adf (patch)
treef161359096a8e5a11630f55d6091e5bad8a44680 /Demo/pysvr/pysvr.c
parent6e614e3d2a94abb329e727ca41bbf4fbba268701 (diff)
downloadcpython-5c8b9911750565713cba39fd8835cc951ddf2adf.zip
cpython-5c8b9911750565713cba39fd8835cc951ddf2adf.tar.gz
cpython-5c8b9911750565713cba39fd8835cc951ddf2adf.tar.bz2
New example of threaded embedding
Diffstat (limited to 'Demo/pysvr/pysvr.c')
-rw-r--r--Demo/pysvr/pysvr.c312
1 files changed, 312 insertions, 0 deletions
diff --git a/Demo/pysvr/pysvr.c b/Demo/pysvr/pysvr.c
new file mode 100644
index 0000000..f6f9e08
--- /dev/null
+++ b/Demo/pysvr/pysvr.c
@@ -0,0 +1,312 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <pthread.h>
+
+/* XXX Umpfh.
+ Python.h defines a typedef destructor, which conflicts with pthread.h.
+ So Python.h must be included after pthread.h. */
+
+#include <Python.h>
+
+#ifndef PORT
+#define PORT 4000
+#endif
+
+extern int optind;
+extern char *optarg;
+extern int getopt();
+
+struct workorder {
+ int conn;
+ struct sockaddr_in addr;
+};
+
+/* Forward */
+static void init_python(void);
+static void usage(void);
+static void oprogname(void);
+static void main_thread(int);
+static void create_thread(int, struct sockaddr_in *);
+static void *service_thread(struct workorder *);
+static void run_interpreter(FILE *, FILE *);
+static int run_command(char *, PyObject *);
+
+static char *progname = "pysvr";
+
+main(int argc, char **argv)
+{
+ int port = PORT;
+ int c;
+
+ if (argc > 0 && argv[0] != NULL && argv[0][0] != '\0')
+ progname = argv[0];
+
+ while ((c = getopt(argc, argv, "")) != EOF) {
+ switch (c) {
+ default:
+ usage();
+ }
+ }
+
+ if (optind < argc) {
+ if (optind+1 < argc) {
+ oprogname();
+ fprintf(stderr, "too many arguments\n");
+ usage();
+ }
+ port = atoi(argv[optind]);
+ if (port <= 0) {
+ fprintf(stderr, "bad port (%s)\n", argv[optind]);
+ usage();
+ }
+ }
+
+ main_thread(port);
+
+ fprintf(stderr, "Bye.\n");
+
+ exit(0);
+}
+
+static char usage_line[] = "usage: %s [port]\n";
+
+static void
+usage()
+{
+ fprintf(stderr, usage_line, progname);
+ exit(2);
+}
+
+static void
+main_thread(int port)
+{
+ int sock;
+ struct sockaddr_in addr;
+
+ sock = socket(PF_INET, SOCK_STREAM, 0);
+ if (sock < 0) {
+ oprogname();
+ perror("can't create socket");
+ exit(1);
+ }
+
+ memset(&addr, '\0', sizeof addr);
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = 0L;
+ if (bind(sock, (struct sockaddr *)&addr, sizeof addr) < 0) {
+ oprogname();
+ perror("can't bind socket to address");
+ exit(1);
+ }
+
+ if (listen(sock, 5) < 0) {
+ oprogname();
+ perror("can't listen on socket");
+ exit(1);
+ }
+
+ fprintf(stderr, "Listening on port %d...\n", port);
+
+ for (;;) {
+ struct sockaddr_in clientaddr;
+ int conn, size;
+
+ conn = accept(sock, (struct sockaddr *) &clientaddr, &size);
+ if (conn < 0) {
+ oprogname();
+ perror("can't accept connection from socket");
+ exit(1);
+ }
+
+ create_thread(conn, &clientaddr);
+ }
+}
+
+static void
+create_thread(int conn, struct sockaddr_in *addr)
+{
+ struct workorder *work;
+ pthread_t tdata;
+
+ work = malloc(sizeof(struct workorder));
+ if (work == NULL) {
+ oprogname();
+ fprintf(stderr, "out of memory for thread.\n");
+ close(conn);
+ return;
+ }
+ work->conn = conn;
+ work->addr = *addr;
+
+ init_python();
+
+ if (pthread_create(&tdata, NULL, (void *)service_thread, work) < 0) {
+ oprogname();
+ perror("can't create new thread");
+ close(conn);
+ return;
+ }
+
+ if (pthread_detach(tdata) < 0) {
+ oprogname();
+ perror("can't detach from thread");
+ }
+}
+
+static PyThreadState *the_tstate;
+static PyInterpreterState *the_interp;
+static PyObject *the_builtins;
+
+static void
+init_python()
+{
+ if (the_interp)
+ return;
+ Py_Initialize(); /* Initialize the interpreter */
+ the_builtins = PyEval_GetBuiltins(); /* Get __builtins__ */
+ PyEval_InitThreads(); /* Create and acquire the interpreter lock */
+ the_tstate = PyEval_SaveThread(); /* Release lock & get thread state */
+ the_interp = the_tstate->interpreter_state; /* Get interp state */
+}
+
+static void *
+service_thread(struct workorder *work)
+{
+ FILE *input, *output;
+
+ fprintf(stderr, "Start thread for connection %d.\n", work->conn);
+
+ input = fdopen(work->conn, "r");
+ if (input == NULL) {
+ oprogname();
+ perror("can't create input stream");
+ goto done;
+ }
+
+ output = fdopen(work->conn, "w");
+ if (output == NULL) {
+ oprogname();
+ perror("can't create output stream");
+ fclose(input);
+ goto done;
+ }
+
+ setvbuf(input, NULL, _IONBF, 0);
+ setvbuf(output, NULL, _IONBF, 0);
+
+ run_interpreter(input, output);
+
+ fclose(input);
+ fclose(output);
+
+ done:
+ fprintf(stderr, "End thread for connection %d.\n", work->conn);
+ close(work->conn);
+ free(work);
+}
+
+static void
+oprogname()
+{
+ int save = errno;
+ fprintf(stderr, "%s: ", progname);
+ errno = save;
+}
+
+static void
+run_interpreter(FILE *input, FILE *output)
+{
+ PyThreadState *tstate;
+ PyObject *new_stdin, *new_stdout;
+ PyObject *old_stdin, *old_stdout, *old_stderr;
+ PyObject *globals;
+ char buffer[1000];
+ char *p, *q;
+ int n, end;
+
+ tstate = PyThreadState_New(the_interp);
+ PyEval_AcquireThread(tstate);
+
+ globals = PyDict_New();
+ PyDict_SetItemString(globals, "__builtins__", the_builtins);
+
+ new_stdin = PyFile_FromFile(input, "<socket-in>", "r", NULL);
+ new_stdout = PyFile_FromFile(output, "<socket-out>", "w", NULL);
+
+ old_stdin = PySys_GetObject("stdin");
+ old_stdout = PySys_GetObject("stdout");
+ old_stderr = PySys_GetObject("stderr");
+
+ for (n = 1; !PyErr_Occurred(); n++) {
+ Py_BEGIN_ALLOW_THREADS
+ fprintf(output, "%d> ", n);
+ p = fgets(buffer, sizeof buffer, input);
+ Py_END_ALLOW_THREADS
+
+ if (p == NULL)
+ break;
+ if (p[0] == '\377' && p[1] == '\354')
+ break;
+
+ q = strrchr(p, '\r');
+ if (q && q[1] == '\n' && q[2] == '\0') {
+ *q++ = '\n';
+ *q++ = '\0';
+ }
+
+ while (*p && isspace(*p))
+ p++;
+ if (p[0] == '#' || p[0] == '\0')
+ continue;
+
+ PySys_SetObject("stdin", new_stdin);
+ PySys_SetObject("stdout", new_stdout);
+ PySys_SetObject("stderr", new_stdout);
+
+ end = run_command(buffer, globals);
+ if (end < 0)
+ PyErr_Print();
+
+ PySys_SetObject("stdin", old_stdin);
+ PySys_SetObject("stdout", old_stdout);
+ PySys_SetObject("stderr", old_stderr);
+
+ if (end)
+ break;
+ }
+
+ Py_XDECREF(globals);
+ Py_XDECREF(new_stdin);
+ Py_XDECREF(new_stdout);
+
+ PyEval_ReleaseThread(tstate);
+ PyThreadState_Delete(tstate);
+
+ fprintf(output, "Goodbye!\n");
+}
+
+static int
+run_command(char *buffer, PyObject *globals)
+{
+ PyObject *m, *d, *v;
+ v = PyRun_String(buffer, Py_single_input, globals, globals);
+ if (v == NULL) {
+ if (PyErr_Occurred() == PyExc_SystemExit) {
+ PyErr_Clear();
+ return 1;
+ }
+ PyErr_Print();
+ return 0;
+ }
+ Py_DECREF(v);
+ return 0;
+}