📄 synth_intr.c
字号:
// when it requires attention, i.e. when one or more of the devices
// want to raise an interrupt. Finding out exactly which interrupt(s)
// are currently pending in the auxiliary requires communication with
// the auxiliary.
//
// If interrupts are currently disabled then the signal cannot be
// handled immediately. In particular SIGIO cannot be handled because
// there may already be ongoing communication with the auxiliary.
// Instead some volatile flags are used to keep track of which signals
// were raised while interrupts were disabled.
//
// It might be better to perform the interaction with the auxiliary
// as soon as possible, i.e. either in the SIGIO handler or when the
// current communication completes. That way the mask of pending
// interrupts would remain up to date even when interrupts are
// disabled, thus allowing applications to run in polled mode.
// A little utility called when the auxiliary has been asked to exit,
// implicitly affecting this application as well. The sole purpose
// of this function is to put a suitably-named function on the stack
// to make it more obvious from inside gdb what is happening.
static void
synth_io_handle_shutdown_request_from_auxiliary(void)
{
cyg_hal_sys_exit(0);
}
static void
synth_io_sighandler(int sig)
{
CYG_PRECONDITION((CYG_HAL_SYS_SIGIO == sig), "Only SIGIO should be handled here");
if (!hal_interrupts_enabled) {
synth_sigio_pending = true;
return;
}
// Interrupts were enabled, but must be blocked before any further processing.
hal_interrupts_enabled = false;
// Update the interrupt status "register" to match pending interrupts
// Contact the auxiliary to find out what interrupts are currently pending there.
// If there is no auxiliary at present, e.g. because it has just terminated
// and things are generally somewhat messy, ignore it.
//
// This code also deals with the case where the user has requested program
// termination. It would be wrong for the auxiliary to just exit, since the
// application could not distinguish that case from a crash. Instead the
// auxiliary can optionally return an additional byte of data, and if that
// byte actually gets sent then that indicates pending termination.
if (synth_auxiliary_running) {
int result;
int actual_len;
unsigned char dummy[1];
synth_auxiliary_xchgmsg(SYNTH_DEV_AUXILIARY, SYNTH_AUXREQ_GET_IRQPENDING, 0, 0,
(const unsigned char*) 0, 0, // The auxiliary does not need any additional data
&result, dummy, &actual_len, 1);
synth_pending_isrs |= result;
if (actual_len) {
// The auxiliary has been asked to terminate by the user. This
// request has now been passed on to the eCos application.
synth_io_handle_shutdown_request_from_auxiliary();
}
}
// If any of the pending interrupts are not masked, invoke the VSR
if (0 != (synth_pending_isrs & ~synth_masked_isrs)) {
(*synth_VSR)();
} else {
hal_interrupts_enabled = true;
}
// The VSR will have invoked interrupt_end() with interrupts
// enabled, and they should still be enabled.
CYG_ASSERT( hal_interrupts_enabled, "Interrupts should still be enabled on return from the VSR");
}
// ----------------------------------------------------------------------------
// Here we define an action to do in the idle thread. For the
// synthetic target it makes no sense to spin eating processor time
// that other processes could make use of. Instead we call select. The
// itimer will still go off and kick the scheduler back into life,
// giving us an escape path from the select. There is one problem: in
// some configurations, e.g. when preemption is disabled, the idle
// thread must yield continuously rather than blocking.
void
hal_idle_thread_action(cyg_uint32 loop_count)
{
#ifndef CYGIMP_HAL_IDLE_THREAD_SPIN
cyg_hal_sys__newselect(0,
(struct cyg_hal_sys_fd_set*) 0,
(struct cyg_hal_sys_fd_set*) 0,
(struct cyg_hal_sys_fd_set*) 0,
(struct cyg_hal_sys_timeval*) 0);
#endif
CYG_UNUSED_PARAM(cyg_uint32, loop_count);
}
// ----------------------------------------------------------------------------
// The I/O auxiliary.
//
// I/O happens via an auxiliary process. During startup this code attempts
// to locate and execute a program ecosynth which should be installed in
// ../libexec/ecosynth relative to some directory on the search path.
// Subsequent I/O operations involve interacting with this auxiliary.
#define MAKESTRING1(a) #a
#define MAKESTRING2(a) MAKESTRING1(a)
#define AUXILIARY "../libexec/ecos/hal/synth/arch/" MAKESTRING2(CYGPKG_HAL_SYNTH) "/ecosynth"
// Is the auxiliary up and running?
cyg_bool synth_auxiliary_running = false;
// The pipes to and from the auxiliary.
static int to_aux = -1;
static int from_aux = -1;
// Attempt to start up the auxiliary. Note that this happens early on
// during system initialization so it is "known" that the world is
// still simple, e.g. that no other files have been opened.
static void
synth_start_auxiliary(void)
{
#define BUFSIZE 256
char filename[BUFSIZE];
const char* path = 0;
int i, j;
cyg_bool found = false;
int to_aux_pipe[2];
int from_aux_pipe[2];
int child;
int aux_version;
#if 1
// Check for a command line argument -io. Only run the auxiliary if this
// argument is provided, i.e. default to traditional behaviour.
for (i = 1; i < cyg_hal_sys_argc; i++) {
const char* tmp = cyg_hal_sys_argv[i];
if ('-' == *tmp) {
// Arguments beyond -- are reserved for use by the application,
// and should not be interpreted by the HAL itself or by ecosynth.
if (('-' == tmp[1]) && ('\0' == tmp[2])) {
break;
}
tmp++;
if ('-' == *tmp) {
// Do not distinguish between -io and --io
tmp++;
}
if (('i' == tmp[0]) && ('o' == tmp[1]) && ('\0' == tmp[2])) {
found = 1;
break;
}
}
}
if (!found) {
return;
}
#else
// Check for a command line argument -ni or -nio. Always run the
// auxiliary unless this argument is given, i.e. default to full
// I/O support.
for (i = 1; i < cyg_hal_sys_argc; i++) {
const char* tmp = cyg_hal_sys_argv[i];
if ('-' == *tmp) {
if (('-' == tmp[1]) && ('\0' == tmp[2])) {
break;
}
tmp++;
if ('-' == *tmp) {
tmp++;
}
if ('n' == *tmp) {
tmp++;
if ('i' == *tmp) {
tmp++;
if ('\0' == *tmp) {
found = 1; // -ni or --ni
break;
}
if (('o' == *tmp) && ('\0' == tmp[1])) {
found = 1; // -nio or --nio
break;
}
}
}
}
}
if (found) {
return;
}
#endif
// The auxiliary must be found relative to the current search path,
// so look for a PATH= environment variable.
for (i = 0; (0 == path) && (0 != cyg_hal_sys_environ[i]); i++) {
const char *var = cyg_hal_sys_environ[i];
if (('P' == var[0]) && ('A' == var[1]) && ('T' == var[2]) && ('H' == var[3]) && ('=' == var[4])) {
path = var + 5;
}
}
if (0 == path) {
// Very unlikely, but just in case.
path = ".:/bin:/usr/bin";
}
found = 0;
while (!found && ('\0' != *path)) { // for every entry in the path
char *tmp = AUXILIARY;
j = 0;
// As a special case, an empty string in the path corresponds to the
// current directory.
if (':' == *path) {
filename[j++] = '.';
path++;
} else {
while ((j < BUFSIZE) && ('\0' != *path) && (':' != *path)) {
filename[j++] = *path++;
}
// If not at the end of the search path, move on to the next entry.
if ('\0' != *path) {
while ((':' != *path) && ('\0' != *path)) {
path++;
}
if (':' == *path) {
path++;
}
}
}
// Now append a directory separator, and then the name of the executable.
if (j < BUFSIZE) {
filename[j++] = '/';
}
while ((j < BUFSIZE) && ('\0' != *tmp)) {
filename[j++] = *tmp++;
}
// If there has been a buffer overflow, skip this entry.
if (j == BUFSIZE) {
filename[BUFSIZE-1] = '\0';
diag_printf("Warning: buffer limit reached while searching PATH for the I/O auxiliary.\n");
diag_printf(" : skipping current entry.\n");
} else {
// filename now contains a possible match for the auxiliary.
filename[j++] = '\0';
if (0 == cyg_hal_sys_access(filename, CYG_HAL_SYS_X_OK)) {
found = true;
}
}
}
#undef BUFSIZE
if (!found) {
diag_printf("Error: unable to find the I/O auxiliary program on the current search PATH\n");
diag_printf(" : please install the appropriate host-side tools.\n");
cyg_hal_sys_exit(1);
}
// An apparently valid executable exists (or at the very least it existed...),
// so create the pipes that will be used for communication.
if ((0 != cyg_hal_sys_pipe(to_aux_pipe)) ||
(0 != cyg_hal_sys_pipe(from_aux_pipe))) {
diag_printf("Error: unable to set up pipes for communicating with the I/O auxiliary.\n");
cyg_hal_sys_exit(1);
}
// Time to fork().
child = cyg_hal_sys_fork();
if (child < 0) {
diag_printf("Error: failed to fork() process for the I/O auxiliary.\n");
cyg_hal_sys_exit(1);
} else if (child == 0) {
cyg_bool found_dotdot;
// There should not be any problems rearranging the file descriptors as desired...
cyg_bool unexpected_error = 0;
// In the child process. Close unwanted file descriptors, then some dup2'ing,
// and execve() the I/O auxiliary. The auxiliary will inherit stdin,
// stdout and stderr from the eCos application, so that functions like
// printf() work as expected. In addition fd 3 will be the pipe from
// the eCos application and fd 4 the pipe to the application. It is possible
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -