[squeak-dev] Help needed with select() socket function and signal handlers in squeakVM

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
6 messages Options
Reply | Threaded
Open this post in threaded view
|

[squeak-dev] Help needed with select() socket function and signal handlers in squeakVM

Mariano Martinez Peck
Hi people: We are developing SqueakDBX, an openDBX (http://www.linuxnetworks.de/doc/index.php/OpenDBX) wrapper, that let us communicate with major relational databases through a common API. OpenDBX is a C library. SqueakDBX uses FFI to call those functions. Now, I am getting an error with a select() invocation in that code.

This is a piece of the openDBX function with the problem:

static int pgsql_odbx_result( odbx_t* handle, odbx_result_t** result, struct timeval* timeout, unsigned long chunk )
{

    struct pgconn* conn = (struct pgconn* ) handle->aux;

    if( timeout != NULL ) {
        fprintf( stdout, "timeval tv_sec value: %d\n", timeout->tv_sec );
        fprintf( stdout, "timeval tv_usec value: %d\n", timeout->tv_usec );
    } else {
        puts("El timeval is null");
    }

......

#ifdef HAVE_SELECT
    if( timeout != NULL && PQisBusy( (PGconn*) handle->generic ) == 1 )
    {
        int fd;
        fd_set fds;

        if( ( fd = PQsocket( (PGconn*) handle->generic ) ) == -1 )
        {
            conn->errtype = -1;
            return -ODBX_ERR_BACKEND;
        }

        FD_ZERO( &fds );
        FD_SET( fd, &fds );

        switch( select( fd + 1, &fds, NULL, NULL, timeout ) )
        {
            case -1:
                printf( "Error with select function: %s\n", strerror( errno ) );
                return -ODBX_ERR_RESULT;
            case 0:
                return ODBX_RES_TIMEOUT;   /* timeout while waiting for a result */
        }
    }
#endif


Now, I have a problem with select() invocation. This function returns -1. And the printf of the errno (where select() stores the errors), says: "Error with select function: Interrupted system call" which means I am getting a EINTR error. If you see console, you can see something like this:

timeval tv_usec value: 0
timeval tv_sec value: 3
timeval tv_usec value: 0
timeval tv_sec value: 2
timeval tv_usec value: 996000
timeval tv_sec value: 3
timeval tv_usec value: 0
Error with select function: Interrupted system call


I asked Norbert (openDBX author) and he tell me exactly this:

"An interrupted system call is something very normal because signals can be sent
at every time to the application, either by the system or by the user. I
guess, in the Squeak code there is some signal handler installed, which does
something if one of the defined signals arrive.

What I will do is to hide the consequences (returning an error) by looking at
the error value and reenter the select call if the system call is interrupted."

All I know is squeakVM is written it SLANG and then that's transformed to C. So, squeakVM runs in C. So, there is where it can be a signal handler ? Is there some way to change that from squeak (image) ?

I am still newbie so I really need help with this.

Thanks for the help in advance.

Mariano



Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Help needed with select() socket function and signal handlers in squeakVM

David T. Lewis
On Sun, Jan 25, 2009 at 08:50:35PM -0200, Mariano Martinez Peck wrote:

>
> Now, I have a problem with select() invocation. This function returns -1.
> And the printf of the errno (where select() stores the errors), says: "Error
> with select function: Interrupted system call" which means I am getting a
> EINTR error. If you see console, you can see something like this:
>
> timeval tv_usec value: 0
> timeval tv_sec value: 3
> timeval tv_usec value: 0
> timeval tv_sec value: 2
> timeval tv_usec value: 996000
> timeval tv_sec value: 3
> timeval tv_usec value: 0
> Error with select function: Interrupted system call
>
>
> I asked Norbert (openDBX author) and he tell me exactly this:
>
> "An interrupted system call is something very normal because signals can be
> sent
> at every time to the application, either by the system or by the user. I
> guess, in the Squeak code there is some signal handler installed, which does
> something if one of the defined signals arrive.
>
> What I will do is to hide the consequences (returning an error) by looking
> at
> the error value and reenter the select call if the system call is
> interrupted."

Norbert is correct, and his solution of reentering the system call sounds
like the right thing to do.

> All I know is squeakVM is written it SLANG and then that's transformed to C.
> So, squeakVM runs in C. So, there is where it can be a signal handler ? Is
> there some way to change that from squeak (image) ?

Any interrupt handler will service interrupts for the entire VM, so this is
not something that you would want to set up for a specific plugin. If one
plugin sets a signal handler, it affects all other plugins as well as the
VM itself.

It is actually quite easy to experiment with setting signal handlers if
you are using a Unix VM and if you have OSProcess installed. For example,
if you want to handle the SIGQUIT signal, you can evualate the expression
'OSProcess accessor forwardSigQuit' to get a Smalltalk semaphore that will be
signalled each time the operating system sends a SIGQUIT (signal number 3)
to the VM. You can have a Squeak process that waits on the semaphore and does
whatever you like.

To be clear however, Norbert's explanation is correct regardless of how
the VM chooses to handle a signal. When a system call such as select is
interrupted, the application (your plugin) needs to check for this and
retry the system call.

HTH,

Dave


Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Help needed with select() socket function and signalhandlers in squeakVM

Gary Chambers-4
Indeed. We did some work with RS485 support for the Serial plugin... EINTRs
happen all the time... recommended to retry (see Linux documentation around
the web as to why). Obviously, in a plugin, the retry can happen quite
quickly. Not sure how using FFI might respond.

Regards, Gary.

----- Original Message -----
From: "David T. Lewis" <[hidden email]>
To: "The general-purpose Squeak developers list"
<[hidden email]>
Sent: Monday, January 26, 2009 1:50 AM
Subject: Re: [squeak-dev] Help needed with select() socket function and
signalhandlers in squeakVM


> On Sun, Jan 25, 2009 at 08:50:35PM -0200, Mariano Martinez Peck wrote:
>>
>> Now, I have a problem with select() invocation. This function returns -1.
>> And the printf of the errno (where select() stores the errors), says:
>> "Error
>> with select function: Interrupted system call" which means I am getting a
>> EINTR error. If you see console, you can see something like this:
>>
>> timeval tv_usec value: 0
>> timeval tv_sec value: 3
>> timeval tv_usec value: 0
>> timeval tv_sec value: 2
>> timeval tv_usec value: 996000
>> timeval tv_sec value: 3
>> timeval tv_usec value: 0
>> Error with select function: Interrupted system call
>>
>>
>> I asked Norbert (openDBX author) and he tell me exactly this:
>>
>> "An interrupted system call is something very normal because signals can
>> be
>> sent
>> at every time to the application, either by the system or by the user. I
>> guess, in the Squeak code there is some signal handler installed, which
>> does
>> something if one of the defined signals arrive.
>>
>> What I will do is to hide the consequences (returning an error) by
>> looking
>> at
>> the error value and reenter the select call if the system call is
>> interrupted."
>
> Norbert is correct, and his solution of reentering the system call sounds
> like the right thing to do.
>
>> All I know is squeakVM is written it SLANG and then that's transformed to
>> C.
>> So, squeakVM runs in C. So, there is where it can be a signal handler ?
>> Is
>> there some way to change that from squeak (image) ?
>
> Any interrupt handler will service interrupts for the entire VM, so this
> is
> not something that you would want to set up for a specific plugin. If one
> plugin sets a signal handler, it affects all other plugins as well as the
> VM itself.
>
> It is actually quite easy to experiment with setting signal handlers if
> you are using a Unix VM and if you have OSProcess installed. For example,
> if you want to handle the SIGQUIT signal, you can evualate the expression
> 'OSProcess accessor forwardSigQuit' to get a Smalltalk semaphore that will
> be
> signalled each time the operating system sends a SIGQUIT (signal number 3)
> to the VM. You can have a Squeak process that waits on the semaphore and
> does
> whatever you like.
>
> To be clear however, Norbert's explanation is correct regardless of how
> the VM chooses to handle a signal. When a system call such as select is
> interrupted, the application (your plugin) needs to check for this and
> retry the system call.
>
> HTH,
>
> Dave
>
>


Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Help needed with select() socket function and signalhandlers in squeakVM

Mariano Martinez Peck
David T. Lewis: Very useful your explanation.

Gary: thanks too.

If fact, I did what you tell we. The problem was that the select() invocation was inside a specific function of OpenDBX. From SqueakDBX the only thing I can do is to call again that function, but this is very different that only call select() function again.

So, what I change openDBX code from this:

        if( ( fd = PQsocket( (PGconn*) handle->generic ) ) == -1 )
        {
            conn->errtype = -1;
            return -ODBX_ERR_BACKEND;
        }

        FD_ZERO( &fds );
        FD_SET( fd, &fds );

        switch( select( fd + 1, &fds, NULL, NULL, timeout ) )



to


    do {

            if( ( fd = PQsocket( (PGconn*) handle->generic ) ) == -1 )
            {
                conn->errtype = -1;
                return -ODBX_ERR_BACKEND;
            }

            FD_ZERO( &fds );
            FD_SET( fd, &fds );
               
            rv = select( fd + 1, &fds, NULL, NULL, timeout );
           
        } while ((rv == -1) && (errno == EINTR));
       
        switch( rv )


And now It works perfect. It was difficult to reproduce because openDBX tests where ok, but squeakDBX ones not. This is because of SqueakVM as you explain me.

So, I am waiting openDBX author feedback about my code, but at least it work!!!

Thanks for the help again.

Mariano


On Mon, Jan 26, 2009 at 8:11 PM, Gary Chambers <[hidden email]> wrote:
Indeed. We did some work with RS485 support for the Serial plugin... EINTRs happen all the time... recommended to retry (see Linux documentation around the web as to why). Obviously, in a plugin, the retry can happen quite quickly. Not sure how using FFI might respond.

Regards, Gary.

----- Original Message ----- From: "David T. Lewis" <[hidden email]>
To: "The general-purpose Squeak developers list" <[hidden email]>
Sent: Monday, January 26, 2009 1:50 AM
Subject: Re: [squeak-dev] Help needed with select() socket function and signalhandlers in squeakVM



On Sun, Jan 25, 2009 at 08:50:35PM -0200, Mariano Martinez Peck wrote:

Now, I have a problem with select() invocation. This function returns -1.
And the printf of the errno (where select() stores the errors), says: "Error
with select function: Interrupted system call" which means I am getting a
EINTR error. If you see console, you can see something like this:

timeval tv_usec value: 0
timeval tv_sec value: 3
timeval tv_usec value: 0
timeval tv_sec value: 2
timeval tv_usec value: 996000
timeval tv_sec value: 3
timeval tv_usec value: 0
Error with select function: Interrupted system call


I asked Norbert (openDBX author) and he tell me exactly this:

"An interrupted system call is something very normal because signals can be
sent
at every time to the application, either by the system or by the user. I
guess, in the Squeak code there is some signal handler installed, which does
something if one of the defined signals arrive.

What I will do is to hide the consequences (returning an error) by looking
at
the error value and reenter the select call if the system call is
interrupted."

Norbert is correct, and his solution of reentering the system call sounds
like the right thing to do.

All I know is squeakVM is written it SLANG and then that's transformed to C.
So, squeakVM runs in C. So, there is where it can be a signal handler ? Is
there some way to change that from squeak (image) ?

Any interrupt handler will service interrupts for the entire VM, so this is
not something that you would want to set up for a specific plugin. If one
plugin sets a signal handler, it affects all other plugins as well as the
VM itself.

It is actually quite easy to experiment with setting signal handlers if
you are using a Unix VM and if you have OSProcess installed. For example,
if you want to handle the SIGQUIT signal, you can evualate the expression
'OSProcess accessor forwardSigQuit' to get a Smalltalk semaphore that will be
signalled each time the operating system sends a SIGQUIT (signal number 3)
to the VM. You can have a Squeak process that waits on the semaphore and does
whatever you like.

To be clear however, Norbert's explanation is correct regardless of how
the VM chooses to handle a signal. When a system call such as select is
interrupted, the application (your plugin) needs to check for this and
retry the system call.

HTH,

Dave







Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Help needed with select() socket function and signalhandlers in squeakVM

David T. Lewis
On Wed, Jan 28, 2009 at 12:51:04AM -0200, Mariano Martinez Peck wrote:

>
> So, what I change openDBX code from this:
>
>         if( ( fd = PQsocket( (PGconn*) handle->generic ) ) == -1 )
>         {
>             conn->errtype = -1;
>             return -ODBX_ERR_BACKEND;
>         }
>
>         FD_ZERO( &fds );
>         FD_SET( fd, &fds );
>
>         switch( select( fd + 1, &fds, NULL, NULL, timeout ) )
>
>
>
> to
>
>
>     do {
>
>             if( ( fd = PQsocket( (PGconn*) handle->generic ) ) == -1 )
>             {
>                 conn->errtype = -1;
>                 return -ODBX_ERR_BACKEND;
>             }
>
>             FD_ZERO( &fds );
>             FD_SET( fd, &fds );
>
>             rv = select( fd + 1, &fds, NULL, NULL, timeout );
>
>         } while ((rv == -1) && (errno == EINTR));
>
>         switch( rv )
>
>
> And now It works perfect. It was difficult to reproduce because openDBX
> tests where ok, but squeakDBX ones not. This is because of SqueakVM as you
> explain me.

Your change looks right to me.

Dave



Reply | Threaded
Open this post in threaded view
|

Re: [squeak-dev] Help needed with select() socket function and signalhandlers in squeakVM

Mariano Martinez Peck
David: Thanks for your help and time!

Norbert (openDBX author) just just tell me this is ok, but checking with PQisBusy() again shouldn't be necessary. So, it was simplified and commited to svn.

Actually now, it is like this:

#ifdef HAVE_SELECT
if( timeout != NULL && PQisBusy( (PGconn*) handle->generic ) == 1 )
{
int fd, err;
fd_set fds;

if( ( fd = PQsocket( (PGconn*) handle->generic ) ) == -1 )
{
conn->errtype = -1;
return -ODBX_ERR_BACKEND;
}

FD_ZERO( &fds );
FD_SET( fd, &fds );

while( ( err = select( fd + 1, &fds, NULL, NULL, timeout ) ) < 0 && errno == EINTR );

switch( err )
{
case -1:
return -ODBX_ERR_RESULT;
case 0:
return ODBX_RES_TIMEOUT; /* timeout while waiting for a result */
}
}
#endif
I test it and works like a charm.

thanks again.

Mariano

On Wed, Jan 28, 2009 at 7:19 PM, David T. Lewis <[hidden email]> wrote:
On Wed, Jan 28, 2009 at 12:51:04AM -0200, Mariano Martinez Peck wrote:
>
> So, what I change openDBX code from this:
>
>         if( ( fd = PQsocket( (PGconn*) handle->generic ) ) == -1 )
>         {
>             conn->errtype = -1;
>             return -ODBX_ERR_BACKEND;
>         }
>
>         FD_ZERO( &fds );
>         FD_SET( fd, &fds );
>
>         switch( select( fd + 1, &fds, NULL, NULL, timeout ) )
>
>
>
> to
>
>
>     do {
>
>             if( ( fd = PQsocket( (PGconn*) handle->generic ) ) == -1 )
>             {
>                 conn->errtype = -1;
>                 return -ODBX_ERR_BACKEND;
>             }
>
>             FD_ZERO( &fds );
>             FD_SET( fd, &fds );
>
>             rv = select( fd + 1, &fds, NULL, NULL, timeout );
>
>         } while ((rv == -1) && (errno == EINTR));
>
>         switch( rv )
>
>
> And now It works perfect. It was difficult to reproduce because openDBX
> tests where ok, but squeakDBX ones not. This is because of SqueakVM as you
> explain me.

Your change looks right to me.

Dave