OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-3.0/] [packages/] [hal/] [synth/] [arch/] [current/] [host/] [ecosynth.c] - Blame information for rev 817

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 786 skrzyp
//============================================================================
2
//
3
//     ecosynth.c
4
//
5
//     The eCos synthetic target I/O auxiliary
6
//
7
//============================================================================
8
// ####ECOSHOSTGPLCOPYRIGHTBEGIN####                                        
9
// -------------------------------------------                              
10
// This file is part of the eCos host tools.                                
11
// Copyright (C) 2002 Free Software Foundation, Inc.                        
12
//
13
// This program is free software; you can redistribute it and/or modify     
14
// it under the terms of the GNU General Public License as published by     
15
// the Free Software Foundation; either version 2 or (at your option) any   
16
// later version.                                                           
17
//
18
// This program is distributed in the hope that it will be useful, but      
19
// WITHOUT ANY WARRANTY; without even the implied warranty of               
20
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU        
21
// General Public License for more details.                                 
22
//
23
// You should have received a copy of the GNU General Public License        
24
// along with this program; if not, write to the                            
25
// Free Software Foundation, Inc., 51 Franklin Street,                      
26
// Fifth Floor, Boston, MA  02110-1301, USA.                                
27
// -------------------------------------------                              
28
// ####ECOSHOSTGPLCOPYRIGHTEND####                                          
29
//============================================================================
30
//#####DESCRIPTIONBEGIN####
31
//
32
// Author(s):   bartv
33
// Contact(s):  bartv
34
// Date:        2002-08-05
35
// Version:     0.01
36
// Description:
37
//
38
// The main module for the eCos synthetic target auxiliary. This
39
// program is fork'ed and execve'd during the initialization phase of
40
// any synthetic target application, and is primarily responsible for
41
// I/O operations. This program should never be run directly by a
42
// user.
43
//
44
//####DESCRIPTIONEND####
45
//============================================================================
46
 
47
#include <stdio.h>
48
#include <stdlib.h>
49
#include <string.h>
50
#include <signal.h>
51
#include <limits.h>
52
#include <unistd.h>
53
#include <assert.h>
54
#include <fcntl.h>
55
#include <sys/param.h>
56
#include <sys/types.h>
57
// Avoid compatibility problems with Tcl 8.4 vs. earlier
58
#define USE_NON_CONST
59
#include <tcl.h>
60
#include <tk.h>
61
 
62
// The protocol between host and target is defined by a private
63
// target-side header.
64
#include "../src/synth_protocol.h"
65
 
66
// ----------------------------------------------------------------------------
67
// Statics etc.
68
#define PROGNAME    "Synthetic target auxiliary"
69
 
70
static int  no_windows = 0; // -nw arg
71
 
72
static pid_t    parent_pid;
73
 
74
// ----------------------------------------------------------------------------
75
// Overview.
76
//
77
// When a synthetic target application is executed, whether directly
78
// or from inside gdb, it can fork() and execve() the synthetic
79
// target auxiliary: this program, ecosynth. For now this is disabled
80
// by default but can be enabled using a --io option on the command line.
81
// In future it may be enabled by default, but can be suppressed using
82
// --nio.
83
//
84
// stdin, stdout, and stderr will be inherited from the eCos application, so
85
// that attempts to use printf() or fprintf(stderr, ) from inside the
86
// auxiliary or its helper applications work as expected. In addition file
87
// descriptor 3 will be a pipe from the eCos application, and file descriptor
88
// 4 will be a pipe to the application. The protocol defined in
89
// ../src/synth_protocol.h runs over these pip
90
//
91
// argv[] and environ are also as per the application, with the exception
92
// of argv[0] which is the full path to this application.
93
//
94
// The bulk of the hard work is done inside Tcl. The C++ code is
95
// responsible only for initialization and for implementing some
96
// additional commands, for example to send a SIGIO signal to the
97
// parent when there is a new pending interrupt. The primary script is
98
// ecosynth.tcl which should be installed alongside the executable.
99
//
100
// This code makes use of the standard Tcl initialization facilities:
101
//
102
// 1) main() calls Tcl_Main() with the command-line arguments and an
103
//    application-specific initialization routine ecosynth_appinit().
104
//
105
// 2) Tcl_Main() goes through the initialization sequence in generic/tclMain.c.
106
//    There is one slight complication: Tcl_main() interprets arguments in
107
//    a way that makes sense for tclsh, but not for ecosynth. Specially if
108
//    argv[1] exists and does not begin with a - then it will be interpreted
109
//    as a script to be executed. Hence argv[] is re-allocated and the name
110
//    of a suitable script is inserted.
111
//
112
// 3) ecosynth_appinit() initializes the Tcl interpreter, and optionally
113
//    the Tk interpreter as well. This is controlled by the presence of
114
//    a -nw argument on the command line. This initialization routine
115
//    also takes care of adding some commands to the Tcl interpreter.
116
//
117
// 4) Tcl_Main() will now proceed to execute the startup script, which
118
//    is eccentric.tcl installed in the libexec directory.
119
 
120
static int  ecosynth_appinit(Tcl_Interp*);
121
 
122
int
123
main(int argc, char** argv)
124
{
125
    char    ecosynth_tcl_path[_POSIX_PATH_MAX];
126
    char**  new_argv;
127
    int     i;
128
 
129
    parent_pid = getppid();
130
 
131
    // The various core Tcl scripts are installed in the same
132
    // directory as ecosynth. The Tcl script itself will check whether
133
    // there is a newer version of itself in the source tree and
134
    // switch to that instead.
135
    assert((strlen(LIBEXECDIR) + strlen(PKG_INSTALL) + 20) < _POSIX_PATH_MAX);
136
    strcpy(ecosynth_tcl_path, LIBEXECDIR);
137
    strcat(ecosynth_tcl_path, "/ecos/");
138
    strcat(ecosynth_tcl_path, PKG_INSTALL);
139
    strcat(ecosynth_tcl_path, "/ecosynth.tcl");
140
 
141
    // Installation sanity checks.
142
    if (0 != access(ecosynth_tcl_path, F_OK)) {
143
        fprintf(stderr, PROGNAME ": error, a required Tcl script has not been installed.\n");
144
        fprintf(stderr, "    The script is \"%s\"\n", ecosynth_tcl_path);
145
        exit(EXIT_FAILURE);
146
    }
147
    if (0 != access(ecosynth_tcl_path, R_OK)) {
148
        fprintf(stderr, PROGNAME ": error, no read access to a required Tcl script.\n");
149
        fprintf(stderr, "    The script is \"%s\"\n", ecosynth_tcl_path);
150
        exit(EXIT_FAILURE);
151
    }
152
 
153
    // Look for options -nw and -w. This information is needed by the appinit() routine.
154
    no_windows = 0;
155
    for (i = 1; i < argc; i++) {
156
        if ((0 == strcmp("-nw", argv[i])) || (0 == strcmp("--nw", argv[i])) ||
157
            (0 == strcmp("-no-windows", argv[i])) || (0 == strcmp("--no-windows", argv[i]))) {
158
            no_windows = 1;
159
        } else if ((0 == strcmp("-w", argv[i])) || (0 == strcmp("--w", argv[i])) ||
160
                   (0 == strcmp("-windows", argv[i])) || (0 == strcmp("--windows", argv[i]))) {
161
            no_windows = 0;
162
        }
163
    }
164
 
165
    new_argv = malloc((argc+2) * sizeof(char*));
166
    if (NULL == new_argv) {
167
        fprintf(stderr, PROGNAME ": internal error, out of memory.\n");
168
        exit(EXIT_FAILURE);
169
    }
170
    new_argv[0] = argv[0];
171
    new_argv[1] = ecosynth_tcl_path;
172
    for (i = 1; i < argc; i++) {
173
        new_argv[i+1] = argv[i];
174
    }
175
    new_argv[i+1] = NULL;
176
 
177
    // Ignore SIGINT requests. Those can happen if e.g. the application is
178
    // ctrl-C'd or if a gdb session is interrupted because this process is
179
    // a child of the eCos application. Instead the normal code for handling
180
    // application termination needs to run.
181
    signal(SIGINT, SIG_IGN);
182
 
183
    // Similarly ignore SIGTSTP if running in graphical mode, it would
184
    // be inappropriate for the GUI to freeze if the eCos application is
185
    // suspended. If running in text mode then it is better for both
186
    // the application and the I/O auxiliary to freeze, halting any further
187
    // output.
188
    if (!no_windows) {
189
        signal(SIGTSTP, SIG_IGN);
190
    }
191
 
192
    Tcl_Main(argc+1, new_argv, &ecosynth_appinit);
193
    return EXIT_SUCCESS;
194
}
195
 
196
 
197
// ----------------------------------------------------------------------------
198
// Commands for the Tcl interpreter. These are few and far between because
199
// as much work as possible is done in Tcl.
200
 
201
// Send a SIGIO signal to the parent process. This is done whenever a new
202
// interrupt is pending. There is a possibility of strange behaviour if
203
// the synthetic target application is exiting at just the wrong moment
204
// and this process has become a zombie. An alternative approach would
205
// involve loading the Extended Tcl extension.
206
static int
207
ecosynth_send_SIGIO(ClientData  clientData __attribute__ ((unused)),
208
                    Tcl_Interp* interp,
209
                    int         argc,
210
                    char**      argv __attribute__ ((unused)))
211
{
212
    if (1 != argc) {
213
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::_send_SIGIO\"" , TCL_STATIC);
214
        return TCL_ERROR;
215
    }
216
 
217
    (void) kill(parent_pid, SIGIO);
218
    return TCL_OK;
219
}
220
 
221
// Similarly send a SIGKILL (-9) to the parent process. This allows the GUI
222
// code to kill of the eCos application
223
static int
224
ecosynth_send_SIGKILL(ClientData clientData __attribute__ ((unused)),
225
                      Tcl_Interp* interp,
226
                      int         argc,
227
                      char**      argv __attribute__ ((unused)))
228
{
229
    if (1 != argc) {
230
        Tcl_SetResult(interp, "wrong # args: should be \"usbtest::_send_SIGIO\"" , TCL_STATIC);
231
        return TCL_ERROR;
232
    }
233
 
234
    (void) kill(parent_pid, SIGKILL);
235
    return TCL_OK;
236
}
237
 
238
 
239
// ----------------------------------------------------------------------------
240
// Application-specific initialization.
241
 
242
static int
243
ecosynth_appinit(Tcl_Interp* interp)
244
{
245
    Tcl_Channel from_app;
246
    Tcl_Channel to_app;
247
 
248
    // Tcl library initialization. This has the effect of executing init.tcl,
249
    // thus setting up package load paths etc. Not all of that initialization
250
    // is necessarily appropriate for ecosynth, but some devices may well want
251
    // to load in additional packages or whatever.
252
    if (Tcl_Init(interp) == TCL_ERROR) {
253
        return TCL_ERROR;
254
    }
255
    // Optionally initialize Tk as well. This can be suppressed by an
256
    // argument -nw. Possibly this could be done by the Tcl script
257
    // instead using dynamic loading.
258
    //
259
    // There is a problem with the way that Tk does its argument processing.
260
    // By default it will accept abbreviations for the standard wish arguments,
261
    // so if the user specifies e.g. -v then the Tk code will interpret this
262
    // as an abbreviation for -visual, and will probably complain because
263
    // -visual takes an argument whereas ecosynth's -v is just a flag.
264
    //
265
    // The Tk argument processing can be suppressed simply by temporarily
266
    // getting rid of the argv variable. The disadvantage is that some
267
    // standard arguments now have to be processed explicitly:
268
    //
269
    //     -colormap map      ignored, of little interest these days
270
    //     -display  display  currently ignored. This would have to be
271
    //                        implemented at the C level, not the Tcl level,
272
    //                        since Tk_Init() will start interacting with the
273
    //                        X server. Its implementation would involve a
274
    //                        setenv() call.
275
    //     -geometry geom     implemented in the Tcl code using "wm geometry"
276
    //     -name     name     ignored for now.
277
    //     -sync              ignored, of little interest to typical users
278
    //     -use      id       ignored, probably of little interest for now
279
    //     -visual   visual   ignored, of little interest these days
280
    //
281
    // so actually the only extra work that is required is for the Tcl code
282
    // to process -geometry.
283
    if (!no_windows) {
284
        Tcl_Obj* argv = Tcl_GetVar2Ex(interp, "argv", NULL, TCL_GLOBAL_ONLY);
285
        Tcl_IncrRefCount(argv);
286
        Tcl_UnsetVar(interp, "argv", TCL_GLOBAL_ONLY);
287
        if (Tk_Init(interp) == TCL_ERROR) {
288
            return TCL_ERROR;
289
        }
290
        Tcl_SetVar2Ex(interp, "argv", NULL, argv, TCL_GLOBAL_ONLY);
291
        Tcl_DecrRefCount(argv);
292
    }
293
 
294
    // Create the synth:: namespace. Currently this does not seem to be possible from
295
    // inside C.
296
    if (TCL_OK != Tcl_Eval(interp,
297
                           "namespace eval synth {\n"
298
                           "    variable channel_from_app 0\n"
299
                           "    variable channel_to_app 0\n"
300
                           "}\n")) {
301
        fprintf(stderr, PROGNAME ": internal error, failed to create Tcl synth:: namespace\n");
302
        fprintf(stderr, "    Please check Tcl version (8.3 or later required).\n");
303
        exit(EXIT_FAILURE);
304
    }
305
 
306
    // The pipe to/from the application is exposed to Tcl, allowing
307
    // the main communication to be handled at the Tcl level and
308
    // specifically via the event loop. This requires two additional
309
    // Tcl channels to be created for file descriptors 3 and 4.
310
    from_app = Tcl_MakeFileChannel((ClientData) 3, TCL_READABLE);
311
    if (NULL == from_app) {
312
        fprintf(stderr, PROGNAME ": internal error, failed to create Tcl channel for pipe from application.\n");
313
        exit(EXIT_FAILURE);
314
    }
315
    Tcl_RegisterChannel(interp, from_app);
316
 
317
    // The channel name will be something like file0. Add a variable to the
318
    // interpreter to store this name.
319
    if (NULL == Tcl_SetVar(interp, "synth::_channel_from_app",  Tcl_GetChannelName(from_app), TCL_GLOBAL_ONLY)) {
320
        fprintf(stderr, PROGNAME ": internal error, failed to create Tcl variable from application channel 0\n");
321
        exit(EXIT_FAILURE);
322
    }
323
 
324
    // Repeat for the channel to the application.
325
    to_app = Tcl_MakeFileChannel((ClientData) 4, TCL_WRITABLE);
326
    if (NULL == to_app) {
327
        fprintf(stderr, PROGNAME ": internal error, failed to create Tcl channel for pipe to application.\n");
328
        exit(EXIT_FAILURE);
329
    }
330
    Tcl_RegisterChannel(interp, to_app);
331
    if (NULL == Tcl_SetVar(interp, "synth::_channel_to_app",  Tcl_GetChannelName(to_app), TCL_GLOBAL_ONLY)) {
332
        fprintf(stderr, PROGNAME ": internal error, failed to create Tcl variable from application channel 1\n");
333
        exit(EXIT_FAILURE);
334
    }
335
 
336
    // The auxiliary may spawn additional programs, via
337
    // device-specific scripts. Those programs should not have
338
    // direct access to the pipe - that would just lead to
339
    // confusion.
340
    fcntl(3, F_SETFD, FD_CLOEXEC);
341
    fcntl(4, F_SETFD, FD_CLOEXEC);
342
 
343
    // Add synthetic target-specific commands to the Tcl interpreter.
344
    Tcl_CreateCommand(interp, "synth::_send_SIGIO", &ecosynth_send_SIGIO, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL);
345
    Tcl_CreateCommand(interp, "synth::_send_SIGKILL", &ecosynth_send_SIGKILL, (ClientData)NULL, (Tcl_CmdDeleteProc*) NULL);
346
 
347
    // Define additional variables.
348
 
349
    // The version, from the AM_INIT_AUTOMAKE() macro in configure.in
350
    Tcl_SetVar(interp, "synth::_ecosynth_version", ECOSYNTH_VERSION, TCL_GLOBAL_ONLY);
351
 
352
    // The parent process id, i.e. that for the eCos application itself.
353
    Tcl_SetVar2Ex(interp, "synth::_ppid", NULL, Tcl_NewIntObj(getppid()), TCL_GLOBAL_ONLY);
354
 
355
    // The various directories
356
    Tcl_SetVar(interp, "synth::_ecosynth_repository", ECOS_REPOSITORY, TCL_GLOBAL_ONLY);
357
    Tcl_SetVar(interp, "synth::_ecosynth_libexecdir", LIBEXECDIR, TCL_GLOBAL_ONLY);
358
    Tcl_SetVar(interp, "synth::_ecosynth_package_dir", PKG_DIR, TCL_GLOBAL_ONLY);
359
    Tcl_SetVar(interp, "synth::_ecosynth_package_version", PKG_VERSION, TCL_GLOBAL_ONLY);
360
    Tcl_SetVar(interp, "synth::_ecosynth_package_install", PKG_INSTALL, TCL_GLOBAL_ONLY);
361
 
362
    return TCL_OK;
363
}

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.