aboutsummaryrefslogtreecommitdiffhomepage
path: root/proc.cpp
diff options
context:
space:
mode:
authorGravatar ridiculousfish <corydoras@ridiculousfish.com>2011-12-26 19:18:46 -0800
committerGravatar ridiculousfish <corydoras@ridiculousfish.com>2011-12-26 19:18:46 -0800
commit8d2f107d61a8b0e099ab9a59b8a32c236da5a5fc (patch)
tree89f718ab74f8400332534aee237c6f925348f05c /proc.cpp
parent3f16ace6784caab54fb054836ee93902e9701913 (diff)
Some changes to migrate towards C++ and a multithreaded model
Diffstat (limited to 'proc.cpp')
-rw-r--r--proc.cpp412
1 files changed, 206 insertions, 206 deletions
diff --git a/proc.cpp b/proc.cpp
index edcc7c69..86c31b52 100644
--- a/proc.cpp
+++ b/proc.cpp
@@ -7,7 +7,7 @@ will call proc to create representations of the running jobs as
needed.
Some of the code in this file is based on code from the Glibc manual.
-
+
*/
#include "config.h"
@@ -76,7 +76,7 @@ Some of the code in this file is based on code from the Glibc manual.
#include "output.h"
/**
- Size of message buffer
+ Size of message buffer
*/
#define MESS_SIZE 256
@@ -85,13 +85,13 @@ Some of the code in this file is based on code from the Glibc manual.
*/
#define BUFFER_SIZE 4096
-/**
- Status of last process to exit
+/**
+ Status of last process to exit
*/
static int last_status=0;
/**
- Signal flag
+ Signal flag
*/
static sig_atomic_t got_signal=0;
@@ -139,7 +139,7 @@ void proc_init()
/**
- Remove job from list of jobs
+ Remove job from list of jobs
*/
static int job_remove( job_t *j )
{
@@ -156,7 +156,7 @@ static int job_remove( job_t *j )
sanity_lose();
return 0;
}
-
+
if( prev == 0 )
first_job = j->next;
else
@@ -184,7 +184,7 @@ void proc_destroy()
{
debug( 2, L"freeing leaked job %ls", first_job->command );
job_free( first_job );
- }
+ }
}
void proc_set_last_status( int s )
@@ -201,25 +201,25 @@ job_t *job_create()
{
int free_id=1;
job_t *res;
-
+
while( job_get( free_id ) != 0 )
free_id++;
- res = halloc( 0, sizeof(job_t) );
+ res = (job_t *)halloc( 0, sizeof(job_t) );
res->next = first_job;
res->job_id = free_id;
first_job = res;
- job_set_flag( res,
- JOB_CONTROL,
- (job_control_mode==JOB_CONTROL_ALL) ||
+ job_set_flag( res,
+ JOB_CONTROL,
+ (job_control_mode==JOB_CONTROL_ALL) ||
((job_control_mode == JOB_CONTROL_INTERACTIVE) && (is_interactive)) );
// if( res->job_id > 2 )
-// fwprintf( stderr, L"Create job %d\n", res->job_id );
+// fwprintf( stderr, L"Create job %d\n", res->job_id );
return res;
}
-
+
job_t *job_get( int id )
{
job_t *res = first_job;
@@ -227,7 +227,7 @@ job_t *job_get( int id )
{
return res;
}
-
+
while( res != 0 )
{
if( res->job_id == id )
@@ -240,7 +240,7 @@ job_t *job_get( int id )
job_t *job_get_from_pid( int pid )
{
job_t *res = first_job;
-
+
while( res != 0 )
{
if( res->pgid == pid )
@@ -251,8 +251,8 @@ job_t *job_get_from_pid( int pid )
}
-/*
- Return true if all processes in the job have stopped or completed.
+/*
+ Return true if all processes in the job have stopped or completed.
\param j the job to test
*/
@@ -271,20 +271,20 @@ int job_is_stopped( const job_t *j )
}
-/*
- Return true if the last processes in the job has completed.
+/*
+ Return true if the last processes in the job has completed.
\param j the job to test
*/
int job_is_completed( const job_t *j )
{
process_t *p;
-
+
for (p = j->first_process; p->next; p = p->next)
;
-
+
return p->completed;
-
+
}
void job_set_flag( job_t *j, int flag, int set )
@@ -301,10 +301,10 @@ int job_get_flag( job_t *j, int flag )
}
int job_signal( job_t *j, int signal )
-{
+{
pid_t my_pid = getpid();
int res = 0;
-
+
if( j->pgid != my_pid )
{
res = killpg( j->pgid, SIGHUP );
@@ -337,7 +337,7 @@ int job_signal( job_t *j, int signal )
/**
Store the status of the process pid that was returned by waitpid.
- Return 0 if all went well, nonzero otherwise.
+ Return 0 if all went well, nonzero otherwise.
*/
static void mark_process_status( job_t *j,
process_t *p,
@@ -345,19 +345,19 @@ static void mark_process_status( job_t *j,
{
// debug( 0, L"Process %ls %ls", p->argv[0], WIFSTOPPED (status)?L"stopped":(WIFEXITED( status )?L"exited":(WIFSIGNALED( status )?L"signaled to exit":L"BLARGH")) );
p->status = status;
-
+
if (WIFSTOPPED (status))
{
p->stopped = 1;
}
- else if (WIFSIGNALED(status) || WIFEXITED(status))
+ else if (WIFSIGNALED(status) || WIFEXITED(status))
{
p->completed = 1;
}
else
{
ssize_t ignore;
-
+
/* This should never be reached */
p->completed = 1;
@@ -388,10 +388,10 @@ static void handle_child_status( pid_t pid, int status )
int found_proc = 0;
job_t *j=0;
process_t *p=0;
-// char mess[MESS_SIZE];
- found_proc = 0;
+// char mess[MESS_SIZE];
+ found_proc = 0;
/*
- snprintf( mess,
+ snprintf( mess,
MESS_SIZE,
"Process %d\n",
(int) pid );
@@ -410,8 +410,8 @@ static void handle_child_status( pid_t pid, int status )
"Process %d is %ls from job %ls\n",
(int) pid, p->actual_cmd, j->command );
write( 2, mess, strlen(mess ));
-*/
-
+*/
+
mark_process_status ( j, p, status);
if( p->completed && prev != 0 )
{
@@ -420,7 +420,7 @@ static void handle_child_status( pid_t pid, int status )
/* snprintf( mess,
MESS_SIZE,
"Kill previously uncompleted process %ls (%d)\n",
- prev->actual_cmd,
+ prev->actual_cmd,
prev->pid );
write( 2, mess, strlen(mess ));
*/
@@ -435,15 +435,15 @@ static void handle_child_status( pid_t pid, int status )
}
- if( WIFSIGNALED( status ) &&
- ( WTERMSIG(status)==SIGINT ||
+ if( WIFSIGNALED( status ) &&
+ ( WTERMSIG(status)==SIGINT ||
WTERMSIG(status)==SIGQUIT ) )
{
if( !is_interactive_session )
- {
+ {
struct sigaction act;
sigemptyset( & act.sa_mask );
- act.sa_flags=0;
+ act.sa_flags=0;
act.sa_handler=SIG_DFL;
sigaction( SIGINT, &act, 0 );
sigaction( SIGQUIT, &act, 0 );
@@ -458,34 +458,34 @@ static void handle_child_status( pid_t pid, int status )
{
c->skip=1;
c=c->outer;
- }
- }
+ }
+ }
}
}
-
+
if( !found_proc )
{
- /*
+ /*
A child we lost track of?
-
+
There have been bugs in both subshell handling and in
builtin handling that have caused this previously...
*/
-/* snprintf( mess,
+/* snprintf( mess,
MESS_SIZE,
"Process %d not found by %d\n",
(int) pid, (int)getpid() );
write( 2, mess, strlen(mess ));
*/
- }
+ }
return;
}
void job_handle_signal ( int signal, siginfo_t *info, void *con )
{
-
+
int status;
pid_t pid;
int errno_old = errno;
@@ -503,19 +503,19 @@ void job_handle_signal ( int signal, siginfo_t *info, void *con )
{
errno=errno_old;
return;
- }
+ }
default:
handle_child_status( pid, status );
break;
}
- }
+ }
kill( 0, SIGIO );
errno=errno_old;
}
-/**
- Format information about job status for the user to look at.
+/**
+ Format information about job status for the user to look at.
\param j the job to test
\param status a string description of the job exit type
@@ -531,46 +531,46 @@ static void format_job_info( const job_t *j, const wchar_t *status )
void proc_fire_event( const wchar_t *msg, int type, pid_t pid, int status )
{
-
+
event.type=type;
event.param1.pid = pid;
-
- al_push( &event.arguments, msg );
+
+ al_push( &event.arguments, msg );
sb_printf( &event_pid, L"%d", pid );
al_push( &event.arguments, event_pid.buff );
-
- sb_printf( &event_status, L"%d", status );
+
+ sb_printf( &event_status, L"%d", status );
al_push( &event.arguments, event_status.buff );
event_fire( &event );
al_truncate( &event.arguments, 0 );
- sb_clear( &event_pid );
- sb_clear( &event_status );
-}
+ sb_clear( &event_pid );
+ sb_clear( &event_status );
+}
int job_reap( int interactive )
{
- job_t *j, *jnext;
+ job_t *j, *jnext;
int found=0;
-
+
static int locked = 0;
-
- locked++;
-
+
+ locked++;
+
/*
job_read may fire an event handler, we do not want to call
ourselves recursively (to avoid infinite recursion).
*/
if( locked>1 )
return 0;
-
+
for( j=first_job; j; j=jnext)
- {
+ {
process_t *p;
jnext = j->next;
-
+
/*
If we are reaping only jobs who do not need status messages
sent to the console, do not consider reaping jobs that need
@@ -580,28 +580,28 @@ int job_reap( int interactive )
{
continue;
}
-
+
for( p=j->first_process; p; p=p->next )
{
int s;
if( !p->completed )
continue;
-
+
if( !p->pid )
- continue;
-
+ continue;
+
s = p->status;
-
- proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, p->pid, ( WIFSIGNALED(s)?-1:WEXITSTATUS( s )) );
-
+
+ proc_fire_event( L"PROCESS_EXIT", EVENT_EXIT, p->pid, ( WIFSIGNALED(s)?-1:WEXITSTATUS( s )) );
+
if( WIFSIGNALED(s) )
{
- /*
+ /*
Ignore signal SIGPIPE.We issue it ourselves to the pipe
writer when the pipe reader dies.
*/
if( WTERMSIG(s) != SIGPIPE )
- {
+ {
int proc_is_job = ((p==j->first_process) && (p->next == 0));
if( proc_is_job )
job_set_flag( j, JOB_NOTIFIED, 1 );
@@ -611,7 +611,7 @@ int job_reap( int interactive )
fwprintf( stdout,
_( L"%ls: Job %d, \'%ls\' terminated by signal %ls (%ls)" ),
program_name,
- j->job_id,
+ j->job_id,
j->command,
sig2wcs(WTERMSIG(p->status)),
signal_get_desc( WTERMSIG(p->status) ) );
@@ -627,43 +627,43 @@ int job_reap( int interactive )
signal_get_desc( WTERMSIG(p->status) ) );
tputs(clr_eol,1,&writeb);
fwprintf (stdout, L"\n" );
- found=1;
+ found=1;
}
-
- /*
+
+ /*
Clear status so it is not reported more than once
*/
p->status = 0;
}
- }
+ }
}
-
- /*
+
+ /*
If all processes have completed, tell the user the job has
- completed and delete it from the active job list.
+ completed and delete it from the active job list.
*/
- if( job_is_completed( j ) )
+ if( job_is_completed( j ) )
{
if( !job_get_flag( j, JOB_FOREGROUND) && !job_get_flag( j, JOB_NOTIFIED ) && !job_get_flag( j, JOB_SKIP_NOTIFICATION ) )
{
format_job_info( j, _( L"ended" ) );
found=1;
}
- proc_fire_event( L"JOB_EXIT", EVENT_EXIT, -j->pgid, 0 );
- proc_fire_event( L"JOB_EXIT", EVENT_JOB_ID, j->job_id, 0 );
+ proc_fire_event( L"JOB_EXIT", EVENT_EXIT, -j->pgid, 0 );
+ proc_fire_event( L"JOB_EXIT", EVENT_JOB_ID, j->job_id, 0 );
job_free(j);
- }
- else if( job_is_stopped( j ) && !job_get_flag( j, JOB_NOTIFIED ) )
+ }
+ else if( job_is_stopped( j ) && !job_get_flag( j, JOB_NOTIFIED ) )
{
- /*
- Notify the user about newly stopped jobs.
+ /*
+ Notify the user about newly stopped jobs.
*/
if( !job_get_flag( j, JOB_SKIP_NOTIFICATION ) )
{
format_job_info( j, _( L"stopped" ) );
found=1;
- }
+ }
job_set_flag( j, JOB_NOTIFIED, 1 );
}
}
@@ -672,8 +672,8 @@ int job_reap( int interactive )
fflush( stdout );
locked = 0;
-
- return found;
+
+ return found;
}
@@ -692,36 +692,36 @@ unsigned long proc_get_jiffies( process_t *p )
wchar_t fn[FN_SIZE];
char state;
- int pid, ppid, pgrp,
+ int pid, ppid, pgrp,
session, tty_nr, tpgid,
- exit_signal, processor;
-
- long int cutime, cstime, priority,
- nice, placeholder, itrealvalue,
+ exit_signal, processor;
+
+ long int cutime, cstime, priority,
+ nice, placeholder, itrealvalue,
rss;
- unsigned long int flags, minflt, cminflt,
- majflt, cmajflt, utime,
- stime, starttime, vsize,
+ unsigned long int flags, minflt, cminflt,
+ majflt, cmajflt, utime,
+ stime, starttime, vsize,
rlim, startcode, endcode,
startstack, kstkesp, kstkeip,
signal, blocked, sigignore,
sigcatch, wchan, nswap, cnswap;
char comm[1024];
-
+
if( p->pid <= 0 )
return 0;
-
+
swprintf( fn, FN_SIZE, L"/proc/%d/stat", p->pid );
-
+
FILE *f = wfopen( fn, "r" );
if( !f )
return 0;
-
- int count = fscanf( f,
- "%d %s %c "
+
+ int count = fscanf( f,
+ "%d %s %c "
"%d %d %d "
"%d %d %lu "
-
+
"%lu %lu %lu "
"%lu %lu %lu "
"%ld %ld %ld "
@@ -735,15 +735,15 @@ unsigned long proc_get_jiffies( process_t *p )
"%lu %lu %lu "
"%lu %d %d ",
-
- &pid, comm, &state,
- &ppid, &pgrp, &session,
+
+ &pid, comm, &state,
+ &ppid, &pgrp, &session,
&tty_nr, &tpgid, &flags,
&minflt, &cminflt, &majflt,
&cmajflt, &utime, &stime,
&cutime, &cstime, &priority,
-
+
&nice, &placeholder, &itrealvalue,
&starttime, &vsize, &rss,
&rlim, &startcode, &endcode,
@@ -765,7 +765,7 @@ unsigned long proc_get_jiffies( process_t *p )
*/
fclose( f );
return utime+stime+cutime+cstime;
-
+
}
/**
@@ -775,14 +775,14 @@ void proc_update_jiffies()
{
job_t *j;
process_t *p;
-
+
for( j=first_job; j; j=j->next )
{
for( p=j->first_process; p; p=p->next )
{
gettimeofday( &p->last_time, 0 );
p->last_jiffies = proc_get_jiffies( p );
- }
+ }
}
}
@@ -791,8 +791,8 @@ void proc_update_jiffies()
/**
Check if there are buffers associated with the job, and select on
- them for a while if available.
-
+ them for a while if available.
+
\param j the job to test
\return 1 if buffers were avaialble, zero otherwise
@@ -804,7 +804,7 @@ static int select_try( job_t *j )
io_data_t *d;
FD_ZERO(&fds);
-
+
for( d = j->io; d; d=d->next )
{
if( d->io_mode == IO_BUFFER )
@@ -816,15 +816,15 @@ static int select_try( job_t *j )
debug( 3, L"select_try on %d\n", fd );
}
}
-
+
if( maxfd >= 0 )
{
int retval;
struct timeval tv;
-
+
tv.tv_sec=0;
tv.tv_usec=10000;
-
+
retval =select( maxfd+1, &fds, 0, 0, &tv );
return retval > 0;
}
@@ -833,7 +833,7 @@ static int select_try( job_t *j )
}
/**
- Read from descriptors until they are empty.
+ Read from descriptors until they are empty.
\param j the job to test
*/
@@ -846,13 +846,13 @@ static void read_try( job_t *j )
*/
for( d = j->io; d; d=d->next )
{
-
+
if( d->io_mode == IO_BUFFER )
{
buff=d;
}
}
-
+
if( buff )
{
debug( 3, L"proc::read_try('%ls')\n", j->command );
@@ -860,7 +860,7 @@ static void read_try( job_t *j )
{
char b[BUFFER_SIZE];
int l;
-
+
l=read_blocked( buff->param1.pipe_fd[0],
b, BUFFER_SIZE );
if( l==0 )
@@ -871,23 +871,23 @@ static void read_try( job_t *j )
{
if( errno != EAGAIN )
{
- debug( 1,
+ debug( 1,
_( L"An error occured while reading output from code block" ) );
- wperror( L"read_try" );
- }
+ wperror( L"read_try" );
+ }
break;
}
else
{
b_append( buff->param2.out_buffer, b, l );
- }
+ }
}
}
}
/**
- Give ownership of the terminal to the specified job.
+ Give ownership of the terminal to the specified job.
\param j The job to give the terminal to.
@@ -897,19 +897,19 @@ static void read_try( job_t *j )
*/
static int terminal_give_to_job( job_t *j, int cont )
{
-
+
if( tcsetpgrp (0, j->pgid) )
{
- debug( 1,
- _( L"Could not send job %d ('%ls') to foreground" ),
- j->job_id,
+ debug( 1,
+ _( L"Could not send job %d ('%ls') to foreground" ),
+ j->job_id,
j->command );
wperror( L"tcsetpgrp" );
return 0;
}
-
+
if( cont )
- {
+ {
if( tcsetattr (0, TCSADRAIN, &j->tmodes))
{
debug( 1,
@@ -926,20 +926,20 @@ static int terminal_give_to_job( job_t *j, int cont )
/**
Returns contol of the terminal to the shell, and saves the terminal
attribute state to the job, so that we can restore the terminal
- ownership to the job at a later time .
+ ownership to the job at a later time .
*/
static int terminal_return_from_job( job_t *j)
{
-
+
if( tcsetpgrp (0, getpgrp()) )
{
debug( 1, _( L"Could not return shell to foreground" ) );
wperror( L"tcsetpgrp" );
return 0;
}
-
- /*
- Save jobs terminal modes.
+
+ /*
+ Save jobs terminal modes.
*/
if( tcgetattr (0, &j->tmodes) )
{
@@ -947,9 +947,9 @@ static int terminal_return_from_job( job_t *j)
wperror( L"tcgetattr" );
return 0;
}
-
- /*
- Restore the shell's terminal modes.
+
+ /*
+ Restore the shell's terminal modes.
*/
if( tcsetattr (0, TCSADRAIN, &shell_modes))
{
@@ -972,35 +972,35 @@ void job_continue (job_t *j, int cont)
job_set_flag( j, JOB_NOTIFIED, 0 );
CHECK_BLOCK();
-
+
debug( 4,
L"Continue job %d, gid %d (%ls), %ls, %ls",
- j->job_id,
+ j->job_id,
j->pgid,
- j->command,
- job_is_completed( j )?L"COMPLETED":L"UNCOMPLETED",
+ j->command,
+ job_is_completed( j )?L"COMPLETED":L"UNCOMPLETED",
is_interactive?L"INTERACTIVE":L"NON-INTERACTIVE" );
-
+
if( !job_is_completed( j ) )
{
if( job_get_flag( j, JOB_TERMINAL ) && job_get_flag( j, JOB_FOREGROUND ) )
- {
+ {
/* Put the job into the foreground. */
int ok;
-
+
signal_block();
-
+
ok = terminal_give_to_job( j, cont );
-
- signal_unblock();
+
+ signal_unblock();
if( !ok )
return;
-
+
}
-
- /*
- Send the job a continue signal, if necessary.
+
+ /*
+ Send the job a continue signal, if necessary.
*/
if( cont )
{
@@ -1025,16 +1025,16 @@ void job_continue (job_t *j, int cont)
{
wperror (L"kill (SIGCONT)");
return;
- }
+ }
}
}
}
-
+
if( job_get_flag( j, JOB_FOREGROUND ) )
{
int quit = 0;
-
- /*
+
+ /*
Wait for job to report. Looks a bit ugly because it has to
handle the possibility that a signal is dispatched while
running job_is_stopped().
@@ -1052,16 +1052,16 @@ void job_continue (job_t *j, int cont)
if( !quit )
{
-
-// debug( 1, L"select_try()" );
+
+// debug( 1, L"select_try()" );
switch( select_try(j) )
{
- case 1:
+ case 1:
{
read_try( j );
break;
}
-
+
case -1:
{
/*
@@ -1072,7 +1072,7 @@ void job_continue (job_t *j, int cont)
improvement on my 300 MHz machine) on
short-lived jobs.
*/
- int status;
+ int status;
pid_t pid = waitpid(-1, &status, WUNTRACED );
if( pid > 0 )
{
@@ -1091,20 +1091,20 @@ void job_continue (job_t *j, int cont)
{
quit = 1;
}
-
+
}
break;
}
-
+
}
- }
+ }
}
- }
+ }
}
-
+
if( job_get_flag( j, JOB_FOREGROUND ) )
{
-
+
if( job_is_completed( j ))
{
process_t *p = j->first_process;
@@ -1113,51 +1113,51 @@ void job_continue (job_t *j, int cont)
if( WIFEXITED( p->status ) || WIFSIGNALED(p->status))
{
- /*
+ /*
Mark process status only if we are in the foreground
and the last process in a pipe, and it is not a short circuted builtin
*/
if( p->pid )
{
int status = proc_format_status(p->status);
-
+
proc_set_last_status( job_get_flag( j, JOB_NEGATE )?!status:status);
}
- }
+ }
}
- /*
- Put the shell back in the foreground.
+ /*
+ Put the shell back in the foreground.
*/
if( job_get_flag( j, JOB_TERMINAL ) && job_get_flag( j, JOB_FOREGROUND ) )
{
int ok;
-
+
signal_block();
ok = terminal_return_from_job( j );
-
+
signal_unblock();
-
+
if( !ok )
return;
-
+
}
}
-
+
}
-int proc_format_status(int status)
+int proc_format_status(int status)
{
- if( WIFSIGNALED( status ) )
+ if( WIFSIGNALED( status ) )
{
return 128+WTERMSIG(status);
- }
- else if( WIFEXITED( status ) )
+ }
+ else if( WIFEXITED( status ) )
{
return WEXITSTATUS(status);
}
return status;
-
+
}
@@ -1165,22 +1165,22 @@ void proc_sanity_check()
{
job_t *j;
job_t *fg_job=0;
-
+
for( j = first_job; j ; j=j->next )
{
process_t *p;
if( !job_get_flag( j, JOB_CONSTRUCTED ) )
continue;
-
-
- validate_pointer( j->command,
- _( L"Job command" ),
+
+
+ validate_pointer( j->command,
+ _( L"Job command" ),
0 );
validate_pointer( j->first_process,
_( L"Process list pointer" ),
0 );
- validate_pointer( j->next,
+ validate_pointer( j->next,
_( L"Job list pointer" ),
1 );
@@ -1191,7 +1191,7 @@ void proc_sanity_check()
{
if( fg_job != 0 )
{
- debug( 0,
+ debug( 0,
_( L"More than one job in foreground: job 1: '%ls' job 2: '%ls'"),
fg_job->command,
j->command );
@@ -1199,39 +1199,39 @@ void proc_sanity_check()
}
fg_job = j;
}
-
+
p = j->first_process;
while( p )
- {
+ {
validate_pointer( p->argv, _( L"Process argument list" ), 0 );
validate_pointer( p->argv[0], _( L"Process name" ), 0 );
validate_pointer( p->next, _( L"Process list pointer" ), 1 );
validate_pointer( p->actual_cmd, _( L"Process command" ), 1 );
-
+
if ( (p->stopped & (~0x00000001)) != 0 )
{
debug( 0,
_( L"Job '%ls', process '%ls' has inconsistent state \'stopped\'=%d" ),
- j->command,
+ j->command,
p->argv[0],
p->stopped );
sanity_lose();
}
-
+
if ( (p->completed & (~0x00000001)) != 0 )
{
debug( 0,
_( L"Job '%ls', process '%ls' has inconsistent state \'completed\'=%d" ),
- j->command,
+ j->command,
p->argv[0],
p->completed );
sanity_lose();
}
-
+
p=p->next;
}
-
- }
+
+ }
}
void proc_push_interactive( int value )