Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 5c8b991

Browse files
committed
New example of threaded embedding
1 parent 6e614e3 commit 5c8b991

4 files changed

Lines changed: 505 additions & 0 deletions

File tree

Demo/pysvr/Makefile

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Makefile for 'pysvr' application embedding Python.
2+
# Tailored for Python 1.5a3 or later.
3+
# Some details are specific to Solaris or CNRI.
4+
5+
# Which C compiler (only set because I don't have cc here)
6+
CC=gcc
7+
8+
# Optimization preferences
9+
OPT=-g
10+
11+
# Where Python is installed, and which version
12+
INST=/usr/local
13+
VER=1.5
14+
15+
# Expressions using the above definitions -- no need to change
16+
PYVER=python$(VER)
17+
#PYC=$(INST)/lib/$(PYVER)/config
18+
PYC=../src/sparc
19+
PYINCL=-I$(INST)/include/$(PYVER) -I$(PYC)
20+
PYLIBS=$(PYC)/libpython1.5.a
21+
22+
# Where GNU readline is installed
23+
RLINST=/depot/gnu/plat
24+
25+
# Libraries to link with -- very installation dependent
26+
RLLIBS=-L$(RLINST)/lib -lreadline -ltermcap
27+
OTHERLIBS=-lsocket -lnsl -lpthread -ldl -lm
28+
29+
# Compilation and link flags -- no need to change normally
30+
CFLAGS=$(PYINCL) $(OPT)
31+
LIBS=$(PYLIBS) $(RLLIBS) $(OTHERLIBS)
32+
33+
# Default port for the pysvr application
34+
PORT=4000
35+
36+
# Default target
37+
all: pysvr
38+
39+
# Target to build pysvr
40+
pysvr: pysvr.o $(PYOBJS)
41+
$(CC) pysvr.o $(LIBS) -o pysvr
42+
43+
# Target to build and run pysvr
44+
run: pysvr
45+
pysvr $(PORT)
46+
47+
# Target to clean up the directory
48+
clean:
49+
-rm -f pysvr *.o *~ core

Demo/pysvr/README

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
This is an example of a multi-threaded C application embedding a
2+
Python interpreter.
3+
4+
The particular application is a multi-threaded telnet-like server that
5+
provides you with a Python prompt (instead of a shell prompt).
6+
7+
The file pysvr.py is a prototype in Python.
8+
9+
THIS APPLICATION IS NOT SECURE -- ONLY USE IT FOR TESTING!

Demo/pysvr/pysvr.c

Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include <ctype.h>
5+
#include <errno.h>
6+
7+
#include <sys/types.h>
8+
#include <sys/socket.h>
9+
#include <netinet/in.h>
10+
11+
#include <pthread.h>
12+
13+
/* XXX Umpfh.
14+
Python.h defines a typedef destructor, which conflicts with pthread.h.
15+
So Python.h must be included after pthread.h. */
16+
17+
#include <Python.h>
18+
19+
#ifndef PORT
20+
#define PORT 4000
21+
#endif
22+
23+
extern int optind;
24+
extern char *optarg;
25+
extern int getopt();
26+
27+
struct workorder {
28+
int conn;
29+
struct sockaddr_in addr;
30+
};
31+
32+
/* Forward */
33+
static void init_python(void);
34+
static void usage(void);
35+
static void oprogname(void);
36+
static void main_thread(int);
37+
static void create_thread(int, struct sockaddr_in *);
38+
static void *service_thread(struct workorder *);
39+
static void run_interpreter(FILE *, FILE *);
40+
static int run_command(char *, PyObject *);
41+
42+
static char *progname = "pysvr";
43+
44+
main(int argc, char **argv)
45+
{
46+
int port = PORT;
47+
int c;
48+
49+
if (argc > 0 && argv[0] != NULL && argv[0][0] != '\0')
50+
progname = argv[0];
51+
52+
while ((c = getopt(argc, argv, "")) != EOF) {
53+
switch (c) {
54+
default:
55+
usage();
56+
}
57+
}
58+
59+
if (optind < argc) {
60+
if (optind+1 < argc) {
61+
oprogname();
62+
fprintf(stderr, "too many arguments\n");
63+
usage();
64+
}
65+
port = atoi(argv[optind]);
66+
if (port <= 0) {
67+
fprintf(stderr, "bad port (%s)\n", argv[optind]);
68+
usage();
69+
}
70+
}
71+
72+
main_thread(port);
73+
74+
fprintf(stderr, "Bye.\n");
75+
76+
exit(0);
77+
}
78+
79+
static char usage_line[] = "usage: %s [port]\n";
80+
81+
static void
82+
usage()
83+
{
84+
fprintf(stderr, usage_line, progname);
85+
exit(2);
86+
}
87+
88+
static void
89+
main_thread(int port)
90+
{
91+
int sock;
92+
struct sockaddr_in addr;
93+
94+
sock = socket(PF_INET, SOCK_STREAM, 0);
95+
if (sock < 0) {
96+
oprogname();
97+
perror("can't create socket");
98+
exit(1);
99+
}
100+
101+
memset(&addr, '\0', sizeof addr);
102+
addr.sin_family = AF_INET;
103+
addr.sin_port = htons(port);
104+
addr.sin_addr.s_addr = 0L;
105+
if (bind(sock, (struct sockaddr *)&addr, sizeof addr) < 0) {
106+
oprogname();
107+
perror("can't bind socket to address");
108+
exit(1);
109+
}
110+
111+
if (listen(sock, 5) < 0) {
112+
oprogname();
113+
perror("can't listen on socket");
114+
exit(1);
115+
}
116+
117+
fprintf(stderr, "Listening on port %d...\n", port);
118+
119+
for (;;) {
120+
struct sockaddr_in clientaddr;
121+
int conn, size;
122+
123+
conn = accept(sock, (struct sockaddr *) &clientaddr, &size);
124+
if (conn < 0) {
125+
oprogname();
126+
perror("can't accept connection from socket");
127+
exit(1);
128+
}
129+
130+
create_thread(conn, &clientaddr);
131+
}
132+
}
133+
134+
static void
135+
create_thread(int conn, struct sockaddr_in *addr)
136+
{
137+
struct workorder *work;
138+
pthread_t tdata;
139+
140+
work = malloc(sizeof(struct workorder));
141+
if (work == NULL) {
142+
oprogname();
143+
fprintf(stderr, "out of memory for thread.\n");
144+
close(conn);
145+
return;
146+
}
147+
work->conn = conn;
148+
work->addr = *addr;
149+
150+
init_python();
151+
152+
if (pthread_create(&tdata, NULL, (void *)service_thread, work) < 0) {
153+
oprogname();
154+
perror("can't create new thread");
155+
close(conn);
156+
return;
157+
}
158+
159+
if (pthread_detach(tdata) < 0) {
160+
oprogname();
161+
perror("can't detach from thread");
162+
}
163+
}
164+
165+
static PyThreadState *the_tstate;
166+
static PyInterpreterState *the_interp;
167+
static PyObject *the_builtins;
168+
169+
static void
170+
init_python()
171+
{
172+
if (the_interp)
173+
return;
174+
Py_Initialize(); /* Initialize the interpreter */
175+
the_builtins = PyEval_GetBuiltins(); /* Get __builtins__ */
176+
PyEval_InitThreads(); /* Create and acquire the interpreter lock */
177+
the_tstate = PyEval_SaveThread(); /* Release lock & get thread state */
178+
the_interp = the_tstate->interpreter_state; /* Get interp state */
179+
}
180+
181+
static void *
182+
service_thread(struct workorder *work)
183+
{
184+
FILE *input, *output;
185+
186+
fprintf(stderr, "Start thread for connection %d.\n", work->conn);
187+
188+
input = fdopen(work->conn, "r");
189+
if (input == NULL) {
190+
oprogname();
191+
perror("can't create input stream");
192+
goto done;
193+
}
194+
195+
output = fdopen(work->conn, "w");
196+
if (output == NULL) {
197+
oprogname();
198+
perror("can't create output stream");
199+
fclose(input);
200+
goto done;
201+
}
202+
203+
setvbuf(input, NULL, _IONBF, 0);
204+
setvbuf(output, NULL, _IONBF, 0);
205+
206+
run_interpreter(input, output);
207+
208+
fclose(input);
209+
fclose(output);
210+
211+
done:
212+
fprintf(stderr, "End thread for connection %d.\n", work->conn);
213+
close(work->conn);
214+
free(work);
215+
}
216+
217+
static void
218+
oprogname()
219+
{
220+
int save = errno;
221+
fprintf(stderr, "%s: ", progname);
222+
errno = save;
223+
}
224+
225+
static void
226+
run_interpreter(FILE *input, FILE *output)
227+
{
228+
PyThreadState *tstate;
229+
PyObject *new_stdin, *new_stdout;
230+
PyObject *old_stdin, *old_stdout, *old_stderr;
231+
PyObject *globals;
232+
char buffer[1000];
233+
char *p, *q;
234+
int n, end;
235+
236+
tstate = PyThreadState_New(the_interp);
237+
PyEval_AcquireThread(tstate);
238+
239+
globals = PyDict_New();
240+
PyDict_SetItemString(globals, "__builtins__", the_builtins);
241+
242+
new_stdin = PyFile_FromFile(input, "<socket-in>", "r", NULL);
243+
new_stdout = PyFile_FromFile(output, "<socket-out>", "w", NULL);
244+
245+
old_stdin = PySys_GetObject("stdin");
246+
old_stdout = PySys_GetObject("stdout");
247+
old_stderr = PySys_GetObject("stderr");
248+
249+
for (n = 1; !PyErr_Occurred(); n++) {
250+
Py_BEGIN_ALLOW_THREADS
251+
fprintf(output, "%d> ", n);
252+
p = fgets(buffer, sizeof buffer, input);
253+
Py_END_ALLOW_THREADS
254+
255+
if (p == NULL)
256+
break;
257+
if (p[0] == '\377' && p[1] == '\354')
258+
break;
259+
260+
q = strrchr(p, '\r');
261+
if (q && q[1] == '\n' && q[2] == '\0') {
262+
*q++ = '\n';
263+
*q++ = '\0';
264+
}
265+
266+
while (*p && isspace(*p))
267+
p++;
268+
if (p[0] == '#' || p[0] == '\0')
269+
continue;
270+
271+
PySys_SetObject("stdin", new_stdin);
272+
PySys_SetObject("stdout", new_stdout);
273+
PySys_SetObject("stderr", new_stdout);
274+
275+
end = run_command(buffer, globals);
276+
if (end < 0)
277+
PyErr_Print();
278+
279+
PySys_SetObject("stdin", old_stdin);
280+
PySys_SetObject("stdout", old_stdout);
281+
PySys_SetObject("stderr", old_stderr);
282+
283+
if (end)
284+
break;
285+
}
286+
287+
Py_XDECREF(globals);
288+
Py_XDECREF(new_stdin);
289+
Py_XDECREF(new_stdout);
290+
291+
PyEval_ReleaseThread(tstate);
292+
PyThreadState_Delete(tstate);
293+
294+
fprintf(output, "Goodbye!\n");
295+
}
296+
297+
static int
298+
run_command(char *buffer, PyObject *globals)
299+
{
300+
PyObject *m, *d, *v;
301+
v = PyRun_String(buffer, Py_single_input, globals, globals);
302+
if (v == NULL) {
303+
if (PyErr_Occurred() == PyExc_SystemExit) {
304+
PyErr_Clear();
305+
return 1;
306+
}
307+
PyErr_Print();
308+
return 0;
309+
}
310+
Py_DECREF(v);
311+
return 0;
312+
}

0 commit comments

Comments
 (0)