]> andersk Git - moira.git/blame - gdb/tsr.c
Diane Delgado's changes for a fixed table-locking order
[moira.git] / gdb / tsr.c
CommitLineData
5580185e 1/*
2 * $Source$
3 * $Header$
4 */
5
6#ifndef lint
7static char *rcsid_tsr_c = "$Header$";
8#endif lint
9
10/************************************************************************/
11/*
12/* tsr (test server)
13/* -----------------
14/*
15/* Author: Noah Mendelsohn (IBM T.J. Watson Research and MIT Project
16/* Athena)
17/*
18/* Copyright: 1986 MIT Project Athena
19/*
20/************************************************************************/
21/*
22/* PURPOSE
23/* -------
24/*
25/* A GDB server program demonstrating techniques for asynchronously
26/* communicating with an arbitrary number of clients from a single
27/* Unix server process. This server accepts GDB connections from
28/* clients as requests come in (up to the arbitrary maximum
29/* MAXCLIENTS.) On each connection, it receives a stream of integers,
30/* which it interprets as ASCII characters. The characters are
31/* converted to uppercase, and then sent back to the client from
32/* which they came.
33/*
34/* All of this is done completely asynchronously. No client is
35/* locked out while characters are being echoed to another, and
36/* new connections are accepted at any time.
37/*
38/* NOTES
39/* -----
40/*
41/* 1) The complete state of each client is kept in the array
42/* named client. The client[i].state variable indicates whether
43/* client i is active, and if so, the client[i].action variable
44/* indicates what kind of asynchronous activity the client is
45/* engaged in. Note that these are local conventions, having
46/* nothing to do with GDB or its interfaces.
47/*
48/* 2) Communication to each client is done over its connection,
49/* named client[i].con.
50/*
51/* 3) There is at most one asynchronous activity pending to
52/* each client at any given time, and its state is tracked
53/* in the variable named client[i].pending_op. The operation
54/* may be a send, a receive, or an accept, depending on
55/* the contents of client[i].action. These operations are
56/* allocated when the server starts up, and then re-used
57/* repeatedly. They are the GDB analog of a lightweight process,
58/* which is activated when queued on a connection.
59/*
60/* 4) A special form of connection and a special listening operation
61/* are used for asynchronously listening for new connection
62/* requests. These are 'listencon' and 'listenop' respectively.
63\f/*
64/* 5) GDB includes a special form of select which waits for
65/* completion of operations as well as for activity on user
66/* specified file descriptors. The list of operations to be
67/* monitored is stored in the variable
68/* named op_list. The call to op_select_any hangs until one
69/* or more of these operations complete, then terminates.
70/*
71/* 6) The main server loop acts on any new connection requests,
72/* processes any newly completed activity on the active
73/* clients, then drops into op_select_any to allow asynchronous
74/* activities to progress.
75/*
76/*
77/************************************************************************/
78
79#include <stdio.h>
80#include "gdb.h"
81
82extern int errno;
83
84\f
85/************************************************************************/
86/*
87/* DECLARATIONS
88/*
89/************************************************************************/
90
91#define MAXCLIENTS 10
92
93 /*----------------------------------------------------------*/
94 /*
95 /* State of each possible client
96 /*
97 /*----------------------------------------------------------*/
98
99struct client {
100 int state; /* state of this client */
101 /* descriptor */
102#define CL_DEAD 1 /* client not started */
103#define CL_STARTING 2 /* accepted, reply ongoing */
104#define CL_UP 3 /* ready to go */
105 int action; /* what are we doing now */
106#define CL_RECEIVE 4 /* waiting for a packet */
107#define CL_SEND 5 /* sending a packet */
108#define CL_ACCEPT 6 /* sending a reply */
109 CONNECTION con; /* connection to this */
110 /* client, if any */
111 OPERATION pending_op; /* pending operation */
112 /* on this connection, */
113 /* if any */
114 int data; /* the character to echo */
115 /* goes here, expressed as */
116 /* an int */
117};
118
119struct client client[MAXCLIENTS];
120
121 /*----------------------------------------------------------*/
122 /*
123 /* Connections and operations for listening for
124 /* new clients.
125 /*
126 /*----------------------------------------------------------*/
127
128CONNECTION listencon; /* listen on this */
129 /* connection */
130OPERATION listenop; /* this operation is used */
131 /* repeatedly for listening */
132 /* for new clients */
133
134int nextcl = 0; /* index of the next client */
135 /* we'll accept */
136
137\f /*----------------------------------------------------------*/
138 /*
139 /* Miscellaneous variables used in acquiring connections.
140 /* These are ignored in a simple server like this; a
141 /* more sophisticated server might want to validate the
142 /* names of its clients before accepting connections.
143 /*
144 /*----------------------------------------------------------*/
145
146TUPLE client_tuple; /* client request goes */
147 /* here */
148char otherside[100];
149int othersize;
150
151
152\f
153/************************************************************************/
154/*
155/* MAIN
156/*
157/************************************************************************/
158
159int
160main(argc, argv)
161int argc;
162char *argv[];
163{
164 /*----------------------------------------------------------*/
165 /*
166 /* LOCAL VARIABLES
167 /*
168 /*----------------------------------------------------------*/
169
170 register int i; /* loop index */
171 LIST_OF_OPERATIONS op_list; /* for op_select_any */
172
173 /*----------------------------------------------------------*/
174 /*
175 /* Check parameters
176 /*
177 /*----------------------------------------------------------*/
178
179 if (argc != 2) {
180 fprintf(stderr,"Correct form is %s <servicename>\n",
181 argv[0]);
182 exit(4);
183 }
184
185 /*----------------------------------------------------------*/
186 /*
187 /* Initialize
188 /*
189 /*----------------------------------------------------------*/
190
191 gdb_init(); /* set up gdb */
192 init_clients(); /* null the client states */
193 do_listen(argv[1]); /* start the listening */
194 /* connection and queue */
195 /* a listening operation */
196 make_oplist(&op_list); /* create wait list */
197
198 /*----------------------------------------------------------*/
199 /*
200 /* Loop forever taking care of business.
201 /*
202 /* 1) If any new connection requests have come in,
203 /* accept them.
204 /*
205 /* 2) For each client on which some activity is newly
206 /* completed, take care of it.
207 /*
208 /*----------------------------------------------------------*/
209
210 while (TRUE) {
211 if (OP_DONE(listenop))
212 new_connection();
213 for (i=0; i<MAXCLIENTS; i++) {
214 if (OP_DONE(client[i].pending_op))
215 do_client(i);
216 }
217 if(op_select_any(op_list, 0, NULL, NULL, NULL, NULL)==(-1)) {
218 perror("op_select_any returned error");
219 exit(32);
220 }
221 }
222}
223\f
224/************************************************************************/
225/*
226/* do_client
227/*
228/* An operation has completed on the specified client.
229/*
230/************************************************************************/
231
232int
233do_client(id)
234int id;
235{
236 register struct client *cp = &(client[id]);
237
238 /*
239 * If there has been an error, shutdown the client.
240 */
241 connection_perror(cp->con, "Unix error on send or receive");
242 /* print error if any */
243 if (connection_status(cp->con) != CON_UP ||
244 OP_STATUS(cp->pending_op) == OP_CANCELLED) {
245 sever_connection(cp->con);
246 reset_operation(cp->pending_op);
247 cp->state = CL_DEAD;
248 cp->action = 0;
249 return;
250 }
251 /*
252 * The operation completed successfully. Figure out what it was
253 * and do the right thing.
254 */
255 switch (cp->action) {
256 case CL_ACCEPT:
257 case CL_SEND:
258 start_receiving_object(cp->pending_op, cp->con,
259 (char *)&cp->data,
260 INTEGER_T);
261 cp->action = CL_RECEIVE;
262 break;
263 case CL_RECEIVE:
264 if (cp->data >= 'a' && cp->data <= 'z')
265 cp->data += 'A'-'a'; /* upcase the response */
266 start_sending_object(cp->pending_op, cp->con,
267 (char *)&cp->data,
268 INTEGER_T);
269 cp->action = CL_SEND;
270 }
271}
272\f
273/************************************************************************/
274/*
275/* init_clients
276/*
277/************************************************************************/
278
279int
280init_clients()
281{
282 register struct client *c;
283
284 for (c=client; c<client+MAXCLIENTS; c++){
285 c->state = CL_DEAD;
286 c->action = 0;
287 c->con = NULL;
288 c->pending_op = create_operation();
289 reset_operation(c->pending_op);
290 }
291}
292
293
294
295/************************************************************************/
296/*
297/* make_oplist
298/*
299/************************************************************************/
300
301int
302make_oplist(oplp)
303LIST_OF_OPERATIONS *oplp;
304{
305 /*
306 * ugh! we've got to fix create_list_of_operations to be
307 * more flexible!!
308 */
309
310 *oplp = create_list_of_operations(MAXCLIENTS+1, listenop,
311 client[0].pending_op,
312 client[1].pending_op,
313 client[2].pending_op,
314 client[3].pending_op,
315 client[4].pending_op,
316 client[5].pending_op,
317 client[6].pending_op,
318 client[7].pending_op,
319 client[8].pending_op,
320 client[9].pending_op);
321}
322\f/************************************************************************/
323/*
324/* do_listen
325/*
326/* Do the one time setup for listening for clients, and
327/* also start a listen for an actual client.
328/*
329/************************************************************************/
330
331int
332do_listen(service)
333char *service;
334{
335
336 /*----------------------------------------------------------*/
337 /*
338 /* Make a listening connection
339 /*
340 /*----------------------------------------------------------*/
341
342 fprintf(stderr, "Server creating listening connection\n");
343 listencon = create_listening_connection(service);
344
345 if (listencon == NULL || connection_status(listencon) != CON_UP) {
346 if(connection_status(listencon) == CON_STOPPING) {
347 connection_perror(listencon,
348 "Unix error creating listening connection");
349 }
350 fprintf(stderr,"tsr: could not create listening connection\n");
351 exit (4);
352 }
353
354 /*----------------------------------------------------------*/
355 /*
356 /* On that connection, put up an operation to listen
357 /* for our first client.
358 /*
359 /*----------------------------------------------------------*/
360
361 listenop = create_operation();
362
363 othersize = sizeof(otherside);
364
365 start_accepting_client(listencon, listenop, &(client[nextcl].con),
366 (char *)otherside,
367 &othersize, &client_tuple);
368
369}
370\f
371/************************************************************************/
372/*
373/* new_connection
374/*
375/* We have just gotten a connection for client nextcl.
376/*
377/************************************************************************/
378
379int
380new_connection()
381{
382 register struct client *cp = &client[nextcl];
383 /*
384 * Make sure there's been no error
385 */
386 if(connection_status(listencon) != CON_UP) {
387 connection_perror(listencon, "Unix error on listening connection");
388 fprintf(gdb_log, "Listening connection has died.\n");
389 exit(8);
390 }
391 if(OP_STATUS(listenop) != OP_COMPLETE ||
392 cp->con == NULL || connection_status(cp->con) != CON_UP) {
393 fprintf(stderr,"Error on listening operation\n");
394 if (cp->con != NULL &&
395 connection_status(cp->con)==CON_STOPPING) {
396 connection_perror(cp->con,
397 "Error on newly started client connection.");
398 sever_connection(cp->con);
399 cp->con = NULL;
400 } else
401 exit(8);
402 } else {
403 /*
404 * Set up the new connection and reply to the client
405 */
406 cp->state = CL_STARTING;
407 cp->action = CL_ACCEPT;
408 start_replying_to_client(cp->pending_op, cp->con, GDB_ACCEPTED,
409 "", "");
410 /*
411 * Find a new free connection descriptor. Blow up if
412 * we've used the last one
413 */
414 for (nextcl=0; nextcl<MAXCLIENTS; nextcl++)
415 if (client[nextcl].state == CL_DEAD)
416 break;
417
418 if (nextcl == MAXCLIENTS) {
419 fprintf(stderr,"Too many clients, giving up\n");
420 exit(8);
421 }
422 }
423 /*
424 * Start listening again
425 */
426 reset_operation(listenop);
427 othersize = sizeof(otherside);
428
429 start_accepting_client(listencon, listenop, &(client[nextcl].con),
430 (char *)otherside,
431 &othersize, &client_tuple);
432
433
434}
This page took 0.131834 seconds and 5 git commands to generate.