PDA

View Full Version : [C/Unix]errore EINTR su semop()


Tommo
18-12-2010, 19:00
Salve,
sto sviluppando una stramaledett* tesina su Unix, e mi trovo a combattere con i semafori.

Apparentemente per nessun motivo, quando chiamo semop() (tutte le volte) la chiamata fallisce con errore EINTR, o "Interruption during the execution of the syscall".
Nello specifico succede quando chiamo per la prima volta sem_wait() dopo la creazione del semaforo.

Ovviamente trattandosi di Unix non è stato possibile trovare documentazione su questo comportamento, quindi chiedo lumi :D

Il codice è questo qua, trattasi di un thin-wrapper per la portabilità (le stesse funzioni le ho implementate anche su win32)


#ifdef _DEBUG
#define NOERROR( T ) _noerror( T, __FUNCTION__, __LINE__ )
#else
#define NOERROR( T ) (T==ERROR ? ERROR : 1)
#endif

int _noerror( int e, const char* func, int line )
{
if( e == ERROR )
{
printf( "Error at %d:%s() \"%s\"\n", line, func, strerror( errno ) );

DEBUG_ASSERT(0);

return ERROR;
}
return 1;
}

int sem_create( int amount )
{
int s;

DEBUG_ASSERT( amount >= 0 );

s = semget( IPC_PRIVATE, 1, 0666 | IPC_CREAT | IPC_EXCL ); //1 solo semaforo

//inizializza il semaforo a "amount" per simulare il comportamento Win32
if( NOERROR( s ) && NOERROR( semctl( s, 0, SETVAL, amount ) ) )
return s;


return -1;
}

int sem_op( int SID, int op )
{
struct sembuf oper;

DEBUG_ASSERT( SID > 0 );

oper.sem_num = 0;
oper.sem_op = op;
oper.sem_flg = 0;

return NOERROR( semop( SID, &oper, 1 ) );
}


int sem_wait( int SID )
{
return sem_op( SID, -1 );
}

int sem_signal( int SID )
{
return sem_op( SID, 1 );
}


Boh.

maulattu
18-12-2010, 20:15
ciao,
hai provato a dare un'occhiata qui?
http://www.advancedlinuxprogramming.com/downloads.html
scaricati il libro, forse è un settaggio errato dei semafori...

Tommo
19-12-2010, 01:52
Purtroppo quel libro cita EINTR una sola volta, e semop() ha una trattazione più ridotta della manpage...

Cmq guardando quelle poche sources che ci sono in giro, ho visto che molti mettono semop() dentro un while, che si ripete finchè l'errore è EINTR.
Che senso ha questo "riprovare all'infinito"?

Also, se non uso gdb le chiamate di threading si comportano in maniera del tutto differente.

I love Linux :asd:

marco.r
19-12-2010, 20:04
EINTR viene ritornato quando viene lanciato un segnale durante la chiamata di sistema.
La man page di semop lo conferma. Che segnali tratti ?
Gdb fa dei smanettamenti con i signal handler per poter gestire l'interruzione del processo debuggato, i comportamenti "diversi" potrebbero essere dovuti a quello; con che chiamate ti succede ? Quali sono i comportamenti inaspettati ?

marco.r
19-12-2010, 20:13
Cmq guardando quelle poche sources che ci sono in giro, ho visto che molti mettono semop() dentro un while, che si ripete finchè l'errore è EINTR.
Che senso ha questo "riprovare all'infinito"?

La chiamata è ritornata perchè interrotta da un segnale. Di per sè non ha fatto niente di male per cui, se fai uso o gestisci segnali, ha senso continuare a riprovare (se la chiamata è bloccante perlomeno).

Tommo
20-12-2010, 00:59
Sembrerebbe che il problema cmq è gbd, perchè se lo faccio girare normalmente va alla perfezione... cioè crasha poco dopo per motivi che senza gdb non posso individuare :D

Mi sa che la versione unix la faccio su OSX :D

marco.r
20-12-2010, 08:36
Dubito che con OSX ti andra' meglio, perche' comunque gdb dovra' installare di signal handler e questi ti faranno fallire la chiamata in attesa.
Prova piuttosto ad usare funzionalita' di tracing (lttng ad esempio) oppure valgrind

Tommo
20-12-2010, 11:11
Almeno su OSX posso steppare nel codice come si deve :asd:

Tommo
23-12-2010, 17:39
struct sembuf oper;
int err;

DEBUG_ASSERT( SID > 0 );

oper.sem_num = 0;
oper.sem_op = op;
oper.sem_flg = 0;

do err = semop( SID, &oper, 1 ); //keep repeating on interruptions
while( errno == EINTR );

return NOERROR( err );


Tutto ciò sembra funzionare... sembra che gdb faccia fallire le chiamate a semop.

A presto per la prossima puntata :asd:

Tommo
27-12-2010, 03:34
Uppo il thread perchè in realtà, solo la Wait funzionava, quindi con op = -1.

Se op = 1 o comunque n > 0, il do while diventa un ciclo infinito, cioè semop da sempre errore EINTR.
Mistero!

marco.r
27-12-2010, 12:46
Uppo il thread perchè in realtà, solo la Wait funzionava, quindi con op = -1.

Se op = 1 o comunque n > 0, il do while diventa un ciclo infinito, cioè semop da sempre errore EINTR.
Mistero!

dalla manpage:

If successful semop() and semtimedop() return 0; otherwise they return -1 with errno indicating the error.

Ma tu controlli direttamente errno senza verificare il valore di err.
La tua chiamata molto probabilmente non fallisce affatto, solo che il valore di errno è indefinito e incidentalmente ha il valore che era stato precedentemente impostato da un'altra chiamata.

Tieni presente anche che

If sem_op is a positive integer, the operation adds this value to the semaphore value (semval). Furthermore, if SEM_UNDO is specified for this operation, the
system updates the process undo count (semadj) for this semaphore. This operation can always proceed — it never forces a process to wait. The calling
process must have alter permission on the semaphore set.

Ovvero con op=1 la chiamata non e' bloccante quindi non c'è bisogno del controllo.
Comunque, qualcosa come il seguente dovrebbe andare meglio (non testato):

do err = semop( SID, &oper, 1 ); //keep repeating on interruptions
while( err && errno == EINTR );

Tommo
27-12-2010, 20:24
Funziona :D
Thanks!