From: Thaddeus L Olczyk
Subject: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <636ojukmo6ai4qjqmuk9rachv8di66oe87@4ax.com>
I sent a little note yesterday about the WCHAN column in the output of
"ps xl". Unfortunately I did not have time to go into details. This
message is to fill in as many details as possible.

This is a problem involving a complicated system involving lisp ( the
particular version is ) cmucl , UNIX/Linux, C++, a library called
expat and a program called (html-)tidy.

The basic problem is simple: a lisp program calls a C++ program and
the C++ finishes executing, but control is not returned to the lisp
program. Instead, the called program goes to sleep apparently waiting
for some UNIX thing to happen. I put a command to write to a file as
the second to last command in the C++ process ( the last command being
main->return 0). The file that it writes in has that last line.
Further complicating things is the fact that the C++ process runs when
called from the commandline or from a bash scripts in as near an
environment as the lisp process as I can duplicate. Since lisp and
bash probably run programs in a similar manner this makes the whole
thing rather problematic.

What I basically need is help with tools I already know about ( ps,
lsof, strace ) to help me diagnose the problem, and suggestions of new
tools that may help with diagnosis.

A detailed description of the problem is this:
From a lisp I call a program called get-refs.
This program is supposed to take a list of html/xhtml/xml documents
and extract the hrefs and the srcs and print them to stdout in a
standard format. [1]
The way this program is called from lisp is:

    (with-open-stream
     (s (process-output 
             (run-program command list :output :stream :error nil)))
     ...


command is the full path name of get-refs and list is the list of
documents ( described by filename, the actual filesystem they are
on is nfs mounted ).

The program get-refs works in the following way:
It reads the list of files and process them one by one.
The processing involves the following:
       The file is copied to a temporary file.
        Pipes are opened and closed.
        A new thread is created.
          In the new thread:
            A fork is called.
            In the child process:
               Pipes are mapped to stdio.
               Other pipes are closed.
               Execve is called on a program called tidy. [2]
            In the main process:
               waitpid is called. When waitpid returns,
               a flag child_finished is changed from true to false.
         In the old thread the followng is executed:
             while(!child_fihished && 
                        data in "stdout" or "stderr" pipes)
	{
	       append_to_stdout_buffer( read_stdout_pipe )
	       append_to_stderr_buffer( read_stderr_pipe )
            }
	before each read, I do a poll of that pipe to make sure it is
	readable. I determine that there is no data in the pipe when
             read returns 0 or poll says the pipe is unreadable.
	
       After the I finish reading the pipe, I pass the output from 
       stderr to a routine that checks whether the document is well
       formed html. If the html is not well formed I fix it, and write
       it to a new temporary file. If the html is well formed, I 
       return to the main loop which passes the output from stdout to
       expat where the links are recovered.

       After processing all files, I print out the links.

Some observations:
1) get-refs seems not to hang on a small file, but hangs when passed
     larger files. Initially get-refs seemed to hang in a similar way 
     from the commandline. It turned out to happen when the loop
     for reading was executed more than once ( for small files the 
     buffers managed to be read in one call ). 
     It turned out that all the pipe was not read. That prevented the
     forked process from returning. 
     While this seems similar, this cannot be the problem since 
     get-refs runs from the commandline or a bash script.
2) The appropriate lines from "ps xl" are: 
>     000   502 16084 16080   9   0  5040 1520 pipe_w S    ?         0:00 /home/cmucl
>     040   502 16086 16084   9   0  5040 1520 do_pol S    ?          0:00 /home/cmucl
Sorry that the command is cutoff.
It's not completely clear what the numbers mean ( VSZ and RSS ) or
what exactly pipe_w and do_pol mean.

3) strace does not work. Doing strace on cmucl produces output which
looks like:

---------------------
strace type output.
cmucl startup output
cmucl prompt
*
Exactly the same thing that you see if you run cmucl without strace.

*(quit)
some strace type output but all the calls made before are not printed.

--------------------
Apparently cmucl hijacks stdio and dumps the output from strace.
      
******************************************************************************
THE LONG AND SHORT OF IT.

This does not seem to be a simple problem with something wrong in just
this part or that. Individual parts work OK on their own, it's when
they are glued together that the problem seems to appear.

So I suspect that standard tools for debugging won't work here.
What I believe I need are tools that probe the guts of linux, like ps
lsof, and strace. I basically need to answer two questions and then
my problem will be solved: 1) What is causing the system to hang.
2) What was done or not done which prevents get-refs from terminating.
Unfortunately the parts of the tools that I need ( of those tools that
I know of ) are rather esoteric and thus poorly documented.

This is also a very complex problem. I need the help of someone who
really knows the internals of UNIX and in particular linux. So if you
don't please don't reply. Keep in mind that any suggestion is going to
be met with the question, "but why does it work on the command line".

PS: There is one thing I do that may be causing the problem ( but it
is ambiguous ), when I create the new thread I assume that pipes are
"shared" across threads. That means that if I have a pipe I created in
one thread, I can close it in either thread but should not close it in
both. ( As opposed to processes where the pipes are not shared, and
I have to close a pipe in both processes. )


[1] The reasons that I write a seperate C++ program are:
        a)Initially I tried a lisp based approach, the approach 
           was too slow. 
        b)I need to process what in some cases are badly formed 
           documents. Many are plain html not xhtml, and some of
           those contain strings like "<" which mean they are net even
           well formed html.
        c)I cannot modify the actual documents.
[2] Since I use expat to parse the documents they need to be in xhtml.
      I use tidy to convert plain html into xhtml. Unfortunately 
      alternatives to expat also have this limitation.

From: Joe Marshall
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <Zg__8.78381$_51.64830@rwcrnsc52.ops.asp.att.net>
"Thaddeus L Olczyk" <······@interaccess.com> wrote in message
·······································@4ax.com...
> The program get-refs works in the following way:
> It reads the list of files and process them one by one.
> The processing involves the following:
>        The file is copied to a temporary file.
>         Pipes are opened and closed.
>         A new thread is created.
>           In the new thread:
>             A fork is called.
>             In the child process:
>                Pipes are mapped to stdio.
>                Other pipes are closed.
>                Execve is called on a program called tidy. [2]
>             In the main process:
>                waitpid is called. When waitpid returns,
>                a flag child_finished is changed from true to false.
>          In the old thread the followng is executed:
>              while(!child_fihished &&
>                         data in "stdout" or "stderr" pipes)
> {
>        append_to_stdout_buffer( read_stdout_pipe )
>        append_to_stderr_buffer( read_stderr_pipe )
>             }
> before each read, I do a poll of that pipe to make sure it is
> readable. I determine that there is no data in the pipe when
>              read returns 0 or poll says the pipe is unreadable.
>

If you are calling the system WAITPID, then the entire process
will be suspended until the child returns, but the child won't return
until the pipe is emptied.

You want to use waitpid with a timeout and put it in the loop that is
emptying the pipes.  (this is what the command line does)
From: Thaddeus L Olczyk
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <ejtoju8bs3477k246g0stgqtuj6ca470gb@4ax.com>
On Mon, 22 Jul 2002 20:53:13 GMT, "Joe Marshall"
<·············@attbi.com> wrote:

>
>"Thaddeus L Olczyk" <······@interaccess.com> wrote in message
>·······································@4ax.com...
>>...
>If you are calling the system WAITPID, then the entire process
>will be suspended until the child returns, but the child won't return
>until the pipe is emptied.
>
>You want to use waitpid with a timeout and put it in the loop that is
>emptying the pipes.  (this is what the command line does)
>
>
>
>
Doh! Not very smart are you.
You obviously didn't read:
>>Keep in mind that any suggestion is going to
>>be met with the question, "but why does it work on the command line".
or even:
>>Further complicating things is the fact that the C++ process runs when
>>called from the commandline or from a bash scripts in as near an
>>environment as the lisp process as I can duplicate. 
which is amasing because this part comes before the part that you
"read",
or:
>>I put a command to write to a file as
>>the second to last command in the C++ process ( the last command being
>>main->return 0). The file that it writes in has that last line.
Which indicates that the second to last statement in the program has
been executed. Not possible if it blocks.

In fact you didn't even bother to read the part that you based your
comment on. If you had you would know that waitpid is in a different
thread from the code that reads from the pipe, so that when waitpid 
blocks it doesn't affect the reading. In fact that's why there are two
threads so I can read and call waitpid at the same time.

I have spent many many hours trying to figure this thing out, with
lots and lots of details and only the most important are in the post.

I don't know if I am smarter than any poster who might reply, I
suspect that I am more focused and meticulous. Assuming that a
particular poster is smarter, I very much doubt that he is so much
smarter that a superficial reading of  5% of a post will match the
hours I put in. ( In fact if he were smarter, he probably would have
red the post thoroughly in the first place. ) If you are going to make
a programming suggestion, then please read the whole post and
take all factors into account. Otherwise I will just keep responding
by revisting parts of my original post to get you up to speed. And
thatwill take days.

The prefered course would seem to be: give me the tools I need to
figure out this problem. Which basically would be ways at getting at
the internals of linux and figure out why it will not "let the process
go".
From: Coby Beck
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <Z40%8.28943$VL4.813030@wagner.videotron.net>
Thaddeus L Olczyk <······@interaccess.com> wrote:
> On Mon, 22 Jul 2002 20:53:13 GMT, "Joe Marshall"
> <·············@attbi.com> wrote:
>
>>
>> "Thaddeus L Olczyk" <······@interaccess.com> wrote in message
>> ·······································@4ax.com...
>>> ...
>> If you are calling the system WAITPID, then the entire process
>> will be suspended until the child returns, but the child won't return
>> until the pipe is emptied.
>>
>> You want to use waitpid with a timeout and put it in the loop that is
>> emptying the pipes.  (this is what the command line does)
>>
>>
> Doh! Not very smart are you.

Boy, I can't wait to try to help...can I be next?

[snip]
> I don't know if I am smarter than any poster who might reply, I
> suspect that I am more focused and meticulous. Assuming that a
> particular poster is smarter, I very much doubt that he is so much
> smarter that a superficial reading of  5% of a post will match the
> hours I put in. ( In fact if he were smarter, he probably would have
> red the post thoroughly in the first place. )

I guess the smartest thing is to let you solve your own problem.

--
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: Joe Marshall
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <d90%8.130485$uw.73173@rwcrnsc51.ops.asp.att.net>
"Thaddeus L Olczyk" <······@interaccess.com> wrote in message
·······································@4ax.com...
>
> Doh! Not very smart are you.

Does insulting people help you solve the problem?

> You obviously didn't read:
> >>Keep in mind that any suggestion is going to
> >>be met with the question, "but why does it work on the command line".
> or even:
> >>Further complicating things is the fact that the C++ process runs when
> >>called from the commandline or from a bash scripts in as near an
> >>environment as the lisp process as I can duplicate.

I did in fact read these statements.  The fact that your C++ process
runs when called from the command line and bash scripts, yet does not
run from lisp, indicates that the lisp process is *not* duplicating
what the bash does.

> >>I put a command to write to a file as
> >>the second to last command in the C++ process ( the last command being
> >>main->return 0). The file that it writes in has that last line.
> Which indicates that the second to last statement in the program has
> been executed. Not possible if it blocks.

True, but you state further on that the program works under certain
circumstances (when the file is short).  There is no indication in your
message that this line is printed when the process hangs.

> In fact you didn't even bother to read the part that you based your
> comment on. If you had you would know that waitpid is in a different
> thread from the code that reads from the pipe, so that when waitpid
> blocks it doesn't affect the reading. In fact that's why there are two
> threads so I can read and call waitpid at the same time.

Perhaps you didn't read my reply.  Waitpid may be blocking the entire
process, not just the thread it was called from.  While I am not running
the version of Linux that you are, this is the documented behavior
of waitpid under IRIX, BSD, and System V (and has been the documented
behavior for quite some time).

> I have spent many many hours trying to figure this thing out, with
> lots and lots of details and only the most important are in the post.
>
> I don't know if I am smarter than any poster who might reply, I
> suspect that I am more focused and meticulous. Assuming that a
> particular poster is smarter, I very much doubt that he is so much
> smarter that a superficial reading of  5% of a post will match the
> hours I put in. ( In fact if he were smarter, he probably would have
> red the post thoroughly in the first place. ) If you are going to make
> a programming suggestion, then please read the whole post and
> take all factors into account. Otherwise I will just keep responding
> by revisting parts of my original post to get you up to speed. And
> that will take days.

I don't need to offer help, and I frankly don't care.  This happens
to be a problem that I have a certain amount of experience in.  The test
code for a project I worked on recently was written in Lisp and it had to
co-ordinate several subprocesses in order to simulate the deployment
environment.  The test code was able to lauch these subprocesses and
collect the output under Linux, HPUX, and Windows NT.

Perhaps you are smarter, more focused and more meticulous than I am.
But my code works and yours doesn't.
From: Thaddeus L Olczyk
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <jhbsjucbt58jkuvmrmksj3cvfa12pqvbqu@4ax.com>
On Mon, 22 Jul 2002 23:01:29 GMT, "Joe Marshall"
<·············@attbi.com> wrote:

>
>"Thaddeus L Olczyk" <······@interaccess.com> wrote in message
>·······································@4ax.com...
>>
>> Doh! Not very smart are you.
>
>Does insulting people help you solve the problem?
>
>> You obviously didn't read:
>> >>Keep in mind that any suggestion is going to
>> >>be met with the question, "but why does it work on the command line".
>> or even:
>> >>Further complicating things is the fact that the C++ process runs when
>> >>called from the commandline or from a bash scripts in as near an
>> >>environment as the lisp process as I can duplicate.
>
>I did in fact read these statements.  The fact that your C++ process
>runs when called from the command line and bash scripts, yet does not
>run from lisp, indicates that the lisp process is *not* duplicating
>what the bash does.
>
Please accept my sympathies on your functional illiterateness.
At no point did I say that the lisp process duplicates a bash process.
What I said was that I tried to duplicate the *environment* that the
C++ process runs from.

I didn't even say that I duplicated the environment I said I came *as
close as I could* to a duplicte environment.

Accept my sympathies for your ineptness in the programming areana.
Even if I did say that I duplicated the process. To presume that the
lisp process is not duplicating what bash does is---well--- out of it.
Both lisp and bash have a finite number of OS calls. Only one set
will run a program in a sperate process. Of course there are small
things here and there that lisp may be doing differently. Obviously
one of these small things is different, and the evidence strongly
suggests that something about the little thing that lisp does
differently is *wrong*. Subsequent evidence just strengthens the case 
that it is a problem on the *lisp* side.
>> >>I put a command to write to a file as
>> >>the second to last command in the C++ process ( the last command being
>> >>main->return 0). The file that it writes in has that last line.
>> Which indicates that the second to last statement in the program has
>> been executed. Not possible if it blocks.
>
>True, but you state further on that the program works under certain
>circumstances (when the file is short).  There is no indication in your
>message that this line is printed when the process hangs.
>
>> In fact you didn't even bother to read the part that you based your
>> comment on. If you had you would know that waitpid is in a different
>> thread from the code that reads from the pipe, so that when waitpid
>> blocks it doesn't affect the reading. In fact that's why there are two
>> threads so I can read and call waitpid at the same time.
>
>Perhaps you didn't read my reply.  Waitpid may be blocking the entire
>process, not just the thread it was called from.  While I am not running
>the version of Linux that you are, this is the documented behavior
>of waitpid under IRIX, BSD, and System V (and has been the documented
>behavior for quite some time).
>
>> I have spent many many hours trying to figure this thing out, with
>> lots and lots of details and only the most important are in the post.
>>
>> I don't know if I am smarter than any poster who might reply, I
>> suspect that I am more focused and meticulous. Assuming that a
>> particular poster is smarter, I very much doubt that he is so much
>> smarter that a superficial reading of  5% of a post will match the
>> hours I put in. ( In fact if he were smarter, he probably would have
>> red the post thoroughly in the first place. ) If you are going to make
>> a programming suggestion, then please read the whole post and
>> take all factors into account. Otherwise I will just keep responding
>> by revisting parts of my original post to get you up to speed. And
>> that will take days.
>
>I don't need to offer help, and I frankly don't care.  This happens
>to be a problem that I have a certain amount of experience in.  The test
>code for a project I worked on recently was written in Lisp and it had to
>co-ordinate several subprocesses in order to simulate the deployment
>environment.  The test code was able to lauch these subprocesses and
>collect the output under Linux, HPUX, and Windows NT.
>
>Perhaps you are smarter, more focused and more meticulous than I am.
>But my code works and yours doesn't.
>
>
From: Joe Marshall
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <Ilw%8.113059$Wt3.99294@rwcrnsc53>
"Thaddeus L Olczyk" <······@interaccess.com> wrote in message
·······································@4ax.com...
>
> Accept my sympathies for your ineptness in the programming areana.

That's a funny use of the word `inept', or are we to understand
that you no longer need help because your program works?

Please let us in on the secret of running a subprocess and
collecting the output!  Use small words so that those of us
that don't have your truly dizzying intellect can understand.

And post the code, too.  I want to compare my inept, working
code with your expertly written, ineffective code to find
out where I went wrong.
From: Thaddeus L Olczyk
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <snatjus19amvpajmnro22gl4c4pco3hsg8@4ax.com>
On Wed, 24 Jul 2002 11:39:20 GMT, "Joe Marshall"
<·············@attbi.com> wrote:

>
>"Thaddeus L Olczyk" <······@interaccess.com> wrote in message
>·······································@4ax.com...
>>
>> Accept my sympathies for your ineptness in the programming areana.
>
>That's a funny use of the word `inept', or are we to understand
>that you no longer need help because your program works?
>
>Please let us in on the secret of running a subprocess and
>collecting the output!  Use small words so that those of us
>that don't have your truly dizzying intellect can understand.
>
>And post the code, too.  I want to compare my inept, working
>code with your expertly written, ineffective code to find
>out where I went wrong.
>
Well. Rather than post the code which is quite large, I will post
a simple test script that reproduces the results. It is (colons put in
front to prevent wrapping ):

-----------------------------------------------------------------------------------
#!/bin/bash
# Fix the above as appropriate.
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
:echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
------------------------------------------------

I replace the program name with the name of this script and manage to
get the same results ( the script hangs ). Thus it is the lisp.
(Others might have to add a few lines. )

How did I get this. Well I piped the output of the C++ program to file
and put echo " " around each line. Lo and behold the resulting script
hangs.

This Aleksandr's comment went a long way to helping me figure out the
problem. The rest came from an irc channel of linux kernel programs.
So I've now found the problem and fixed it.

For the most part I've managed to do it without having to have my boss
pay $10,000, $100,000 a seat or whatever for ACL where things like
run-program work perfectly. Or pay that large sum for expensive
technical support. All I needed was a little advice on the more
esoteric tools that help one debug a problem on linux. 

So I put in about fifteen hours about ten of those asking around, and
in the process acquired a whole set of tools useful in debugging
subtle linux problems.

As for your code, when I finished, I came to a realization. You really
stink at linux not to know that waitpid does not block all threads.
And that is one of the platforms your software runs on now. Lack
of this understanding probably causes your software to run slower than
what I would have written in your shoes. Come to think of it, since
all modern UNICES  don't block all threads when one blocks, that can
be
said of all the UNIX platforms you wrote your software for.

But your whole attitude is just getting plain boring, and I have
better things to do than listen to some pathetic nonothing wannabe
programmer. So:
<plonk>
From: Joe Marshall
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <OOz%8.115268$Wt3.99854@rwcrnsc53>
"Thaddeus L Olczyk" <······@interaccess.com> wrote in message
·······································@4ax.com...
> On Wed, 24 Jul 2002 11:39:20 GMT, "Joe Marshall"
> <·············@attbi.com> wrote:
>
>
> Well. Rather than post the code which is quite large, I will post
> a simple test script that reproduces the results. It is (colons put in
> front to prevent wrapping ):
>
> -----------------------------------------------------------------------------------
> #!/bin/bash
> # Fix the above as appropriate.
> :echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

[281 copies of the above line elided]

I stand in awe of your programming prowess.

> But your whole attitude is just getting plain boring, and I have
> better things to do than listen to some pathetic nonothing wannabe
> programmer.  So:
> <plonk>

Damn.  And I was so looking forward to learning something from a
self-acknowledged master of both Lisp and modern Unix systems.
From: Aleksandr Skobelev
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <m3adohhrzd.fsf@list.ru>
After playing aroung your script I found that you just tried to wait for
a child process that waited for you to read from a pipe. You just
shouldn't wait for. So it is enough to add ":wait nil" to the form in
your program to fix the problem:

 (with-open-stream   
   (s (process-output 
       (run-program command list :output :stream :error nil :wait nil)))
     ...


With such changes all works just fine.

Thaddeus L Olczyk <······@interaccess.com> writes:

[...]

> Well. Rather than post the code which is quite large, I will post
> a simple test script that reproduces the results. It is (colons put in
> front to prevent wrapping ):
> 
> --------------------------------------------------------------------------
> #!/bin/bash
> # Fix the above as appropriate.
> :echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
> :echo "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

[...]
From: Nils Goesche
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <lkd6tdmh8l.fsf@pc022.bln.elmeg.de>
Thaddeus L Olczyk <······@interaccess.com> writes:

> >> Doh! Not very smart are you.

> Please accept my sympathies on your functional illiterateness.

> Accept my sympathies for your ineptness in the programming areana.

> >> I don't know if I am smarter than any poster who might reply, I
> >> suspect that I am more focused and meticulous.

Are you operating with the same personality right now as when you were
not even able to write a non-quadratic REMOVE-DUPLICATES?

Regards,
-- 
Nils Goesche
"Don't ask for whom the <CTRL-G> tolls."

PGP key ID 0x42B32FC9
From: Thaddeus L Olczyk
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <r39tju427e5frf0eq7jaiat7bsilin25sr@4ax.com>
On 24 Jul 2002 14:40:26 +0200, Nils Goesche <······@cartan.de> wrote:

>Thaddeus L Olczyk <······@interaccess.com> writes:
>
>> >> Doh! Not very smart are you.
>
>> Please accept my sympathies on your functional illiterateness.
>
>> Accept my sympathies for your ineptness in the programming areana.
>
>> >> I don't know if I am smarter than any poster who might reply, I
>> >> suspect that I am more focused and meticulous.
>
>Are you operating with the same personality right now as when you were
>not even able to write a non-quadratic REMOVE-DUPLICATES?
>
>Regards,
Nils get your facts straight. In the very first post I on that subject
I described a linear algorithm. The people who could not provide a
non-quadratic remove-duplicated were the people implementing it
for compilers, and yes I did *time* it and it was quadratic. To be
fair to the implementors, I was interested in implementing a version
for sorted lists ( which should be much more efficient, all the
duplicates are next to each other ), they have to implement a generic
version.

It was implementing the linear algorithm without excessive overhead
( especially excessive consing ) that I "had difficulty" with. Now
some might think it a bad thing to ask, but should lisp ever become
even slightly popular ( which I doubt having observed the attitude of
this group ) you will have enrty level programmers in lisp writing
code which probably conses up the ass. Those programmers will never
think of asking for help here, and their sloppiness will once again
earn lisp a reputation as a slow language.

So I don't mind asking questions on how to avoid consing.
From: Tim Bradshaw
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <ey365z2nuo2.fsf@cley.com>
* Thaddeus L Olczyk wrote:
> It was implementing the linear algorithm without excessive overhead
> ( especially excessive consing ) that I "had difficulty" with. Now
> some might think it a bad thing to ask, but should lisp ever become
> even slightly popular ( which I doubt having observed the attitude of
> this group ) you will have enrty level programmers in lisp writing
> code which probably conses up the ass. Those programmers will never
> think of asking for help here, and their sloppiness will once again
> earn lisp a reputation as a slow language.

And it was that, combined with your rudeness both then and later that
really blew your chances of being taken seriously on cll, at least.

Rudeness of the kind you have demonstrated is really not forgivable,
of course, but at least on cll people get forgiven a lot.  What they
don't get forgiven is this kind of behaviour *when combined with
asking questions the answer to which should be an easy exercise for an
undergraduate*. If I was teaching CL, I'd expect to get an answer
something like RD/SORTED/SIMPLE below (having phrased the question so
I didn't expect the KW args or varying types).  It doesn't take much
knowledge of Lisp to see that this is not allocating anything it
needn't.  For a more advanced course I might ask something which would
evince the second answer (giving most marks for the non-optimized one,
and some extra for spotting the no-keywords-given case and smashing
that).  This just isn't hard code to write, and failing to be able to
write it *and then being offensive* means people will not hold you in
high regard.

--tim
--cut--

;;;;
;;;

;;; Not heavily tested, typos may remain

(in-package :cl-user)

(defun remove-duplicates/sorted (list &key
                                      (test #'eql testp)
                                      (key #'identity keyp)
                                      (test-not nil test-not-p)
                                      (start nil startp)
                                      (end nil endp)
                                      (from-end nil from-end-p))
  ;; If the list is sorted by something that respects TEST then for
  ;; any two adjacent elts e1 and e2, then either they satisfy TEST,
  ;; or neither e2 nor any elements after it satisfy TEST with e1 or
  ;; any element before it.  In this case, e2 is an element we have
  ;; not yet seen.
  (declare (ignorable test-not start end from-end))
  (declare (type list list))
  (when (or test-not-p startp endp from-end-p)
    (error "Sorry, you need to implement this..."))
  (unless (listp list)
    (error "Only work for lists"))
  (if (null list)
      ;; if the list is empty just return it. This means that the code
      ;; below can always assume at least one eltl, and thus avoid
      ;; boundary
      ;; cases.
      '()
    (if (or testp keyp)
        ;; punt to the full version
        (cons (first list)
              (loop with prev = (funcall key (first list))
                    for e in list
                    for curr = (funcall key e)
                    unless (funcall test curr prev)
                    collect e
                    and do (setf prev curr)))
      ;; Optimized version: if no test is given, and no key is given
      ;; then
      ;; we can use this, which the compiler can probably do a better
      ;; job at
      ;; (inlining EQL &c)
      (cons (first list)
            (loop with prev = (first list)
                  for curr in list
                  unless (eql curr prev)
                  collect curr
                  and do (setf prev curr))))))
                                          
(defun rd/sorted/simple (list)
  ;; simple version: test is EQL, KEY is IDENTITY
  (if (null list)
      ;; if the list is empty just return it. This means that the code
      ;; below can always assume at least one eltl, and thus avoid
      ;; boundary
      ;; cases.
      '()
    (cons (first list)
          (loop with prev = (first list)
                for curr in list
                unless (eql curr prev)
                collect curr
                and do (setf prev curr)))))
From: Thaddeus L Olczyk
Subject: waitpid, blocking and threads ( Re: Complicated system, process hangs when called from cmucl. )
Date: 
Message-ID: <2jatjugffkl2g0eeej4ad0tf6lbufinrdp@4ax.com>
On Mon, 22 Jul 2002 23:01:29 GMT, "Joe Marshall"
<·············@attbi.com> wrote:

>
>> In fact you didn't even bother to read the part that you based your
>> comment on. If you had you would know that waitpid is in a different
>> thread from the code that reads from the pipe, so that when waitpid
>> blocks it doesn't affect the reading. In fact that's why there are two
>> threads so I can read and call waitpid at the same time.
>
>Perhaps you didn't read my reply.  Waitpid may be blocking the entire
>process, not just the thread it was called from.  While I am not running
>the version of Linux that you are, this is the documented behavior
>of waitpid under IRIX, BSD, and System V (and has been the documented
>behavior for quite some time).

You need a lesson in threads. All these systems predate threads. As a
result early versions used user-level threads ( also known as N to 1
schedualing according to Kleiman, Shah, and Smaalders [1] ).
A call to anything that blocks would result in all threads blocking.

I can't speak for IRIX ( my understanding is that SGI has basically
set it adrift ) and System V, but BSD now supports kernel level
threads. As a result, waitpid no longer blocks all threads ( and this 
is reflected allthough not explicitly stated in [1] ).

Java went through the same sort of thing in it's early days. I belive
they called it "green threads" ( though my Java is rusty ).

Further this is not the behaviour prescribed in POSIX and if this was
ever the case for linux it has not been such for at least 5 years.

BTW it is *enormously* stupid to claim that something is
" the documented behavior for quite some time". After all you
could say that about puched cards, token ring and using TV's
as monitors.

[1] Programming with Threads Steve Klieman, Devang Shah, Bart
Smaalders 1996.
From: Aleksandr Skobelev
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <m3ofcyoqm2.fsf@list.ru>
Just some suggestions:

1) You could run strace instead of your program from CMUCL. For example:
* (ext:run-program "/usr/bin/strace" '("-ols.strace"  "ls")  :output t)


2) You could attach gdb to your hanging process. For example, if PID of
   your hanging get-refs process is 1234, then you can try the follow:

$> gdb get-refs
GNU gdb 5.2
Copyright 2002 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i686-pc-linux-gnu"...
(gdb) attach 1234
    
    


Thaddeus L Olczyk <······@interaccess.com> writes:


[...]

> The basic problem is simple: a lisp program calls a C++ program and
> the C++ finishes executing, but control is not returned to the lisp
> program. Instead, the called program goes to sleep apparently waiting
> for some UNIX thing to happen. I put a command to write to a file as
> the second to last command in the C++ process ( the last command being
> main->return 0). The file that it writes in has that last line.
> Further complicating things is the fact that the C++ process runs when
> called from the commandline or from a bash scripts in as near an
> environment as the lisp process as I can duplicate. Since lisp and
> bash probably run programs in a similar manner this makes the whole
> thing rather problematic.
> 
> What I basically need is help with tools I already know about ( ps,
> lsof, strace ) to help me diagnose the problem, and suggestions of new
> tools that may help with diagnosis.
> 

[...]
From: Thaddeus L Olczyk
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <7ifsjucc34kasmkkttb9l1rs27bel0k67k@4ax.com>
On 23 Jul 2002 11:22:45 +0400, Aleksandr Skobelev
<···········@list.ru> wrote:

>Just some suggestions:
>
>1) You could run strace instead of your program from CMUCL. For example:
>* (ext:run-program "/usr/bin/strace" '("-ols.strace"  "ls")  :output t)
Running strace from my program did occur to me. The part that didn't
occur to me was using the -o option of strace ( I didn't know about it
).
>
>
>2) You could attach gdb to your hanging process. For example, if PID of
>   your hanging get-refs process is 1234, then you can try the follow:
>
Since get-refs exits I'm not sure this will work, but it is worth a
shot. It is also worth using on other problems. Do you know if you can
attach from the GUI debuggers like ddd or gvd ( or even gud ).
From: Ingvar Mattsson
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <87sn29s9ce.fsf@gruk.tech.ensign.ftech.net>
Thaddeus L Olczyk <······@interaccess.com> writes:

> On 23 Jul 2002 11:22:45 +0400, Aleksandr Skobelev
> <···········@list.ru> wrote:
> 
> >Just some suggestions:
> >
> >1) You could run strace instead of your program from CMUCL. For example:
> >* (ext:run-program "/usr/bin/strace" '("-ols.strace"  "ls")  :output t)
> Running strace from my program did occur to me. The part that didn't
> occur to me was using the -o option of strace ( I didn't know about it
> ).

From the description I've seen, it does seem to be a filled pipe,
somewhere. Not sure, but that's what I've had when I've had similar
problems.

> >2) You could attach gdb to your hanging process. For example, if PID of
> >   your hanging get-refs process is 1234, then you can try the follow:
> >
> Since get-refs exits I'm not sure this will work, but it is worth a
> shot. It is also worth using on other problems. Do you know if you can
> attach from the GUI debuggers like ddd or gvd ( or even gud ).

Yes, to attach from GUD-gdb, start gdb as "gdb <binary> <pid>", you
most probably will end up somewhere in the middle of the binary and
will have to look at the call tree to determine a good place for a
breakpoint, though.

//Ingvar
-- 
Sysadmin is brave
Machine is running for now
Backup on Friday
From: Thaddeus L Olczyk
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <ms8tju42263vc6fqs2ng3nl5j1bnu1ku4r@4ax.com>
On 24 Jul 2002 11:34:25 +0100, Ingvar Mattsson
<······@cathouse.bofh.se> wrote:

>> >1) You could run strace instead of your program from CMUCL. For example:
>> >* (ext:run-program "/usr/bin/strace" '("-ols.strace"  "ls")  :output t)
>> Running strace from my program did occur to me. The part that didn't
>> occur to me was using the -o option of strace ( I didn't know about it
>> ).
>
>From the description I've seen, it does seem to be a filled pipe,
>somewhere. Not sure, but that's what I've had when I've had similar
>problems.
Yep. I get a list of pipes from lsof, so I know there is still
something there, but don't know what. It would be nice if I could spy
on the pipes and see what's still in there. Then figure out why it's
still in there. Fortunately some explained that in the
/rpc/*pid*/fd/*fd* where the *'d values are the actual integer values
is where the OS keeps the stuff associated with a particular file
system. The problme now is that I have no way of reading it.
cat or more flush the stuff out.

 
From: Aleksandr Skobelev
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <m37kjlnm40.fsf@list.ru>
Thaddeus L Olczyk <······@interaccess.com> writes:

> On 23 Jul 2002 11:22:45 +0400, Aleksandr Skobelev
> <···········@list.ru> wrote:
> 
> >Just some suggestions:
> >
> >1) You could run strace instead of your program from CMUCL. For example:
> >* (ext:run-program "/usr/bin/strace" '("-ols.strace"  "ls")  :output t)
> Running strace from my program did occur to me. The part that didn't
> occur to me was using the -o option of strace ( I didn't know about it
> ).

Hmm. How about man pages? :) 

> >
> >
> >2) You could attach gdb to your hanging process. For example, if PID of
> >   your hanging get-refs process is 1234, then you can try the follow:
> >
> Since get-refs exits I'm not sure this will work, but it is worth a
> shot. It is also worth using on other problems. Do you know if you can
> attach from the GUI debuggers like ddd or gvd ( or even gud ).

I must admit that I've read your message not enough thoroughly. :( 
I don't know about gvd (I've never used it), but I know (and I've just
tried it) that both DDD and GUD allow to attach to running process (what
is not surprising for they both use gdb :).
From: Daniel Barlow
Subject: Re: Complicated system, process hangs when called from cmucl.
Date: 
Message-ID: <87fzy87npf.fsf@noetbook.telent.net>
Aleksandr Skobelev <···········@list.ru> writes:

> Hmm. How about man pages? :) 

Why would a self-described "focused and meticulous" programmer want
to read man pages?  



-dan

-- 

  http://ww.telent.net/cliki/ - Link farm for free CL-on-Unix resources