sem_timedwait n'est pas correctement pris en charge à partir de RedHat Enterprise Linux 5.3 ?

StackOverflow https://stackoverflow.com/questions/1832395

Question

Nous constatons un comportement étrange sur les systèmes RedHat Enterprise Linux avec pthreads sem_timedwait.Cela ne se produit qu'à partir de la version 5.3.

Lorsque nous créons le sémaphore sur un thread d'arrière-plan avec sem_init, aucune erreur n'est renvoyée.Lorsque nous effectuons sem_timedwait, nous obtenons un retour immédiat avec errno = 38 (ENOSYS) indiquant qu'il n'est pas pris en charge.

Si nous faisons la même chose sur le thread principal, cela fonctionne comme prévu et nous n'obtenons aucune erreur de sem_timedwait.

Nous ne le voyons pas sur RHEL 5.2 ou avant.Nous avons essayé de compiler notre code avec gcc 3.2.3 et 4.1.2 et obtenons le même résultat, cela semble donc être un problème d'exécution.

Alors, mes questions (enfin ;)

1) quelqu'un d'autre a vu ça ?2) est-ce un problème connu avec RHEL 5.3 et versions ultérieures ?3) nous utilisons sem_timedwait pour mettre en veille un seul thread.Quelles alternatives existe-t-il sous Linux pour faire la même chose ?

S'il s'agit d'un double d'une autre question, faites-le-moi savoir.J'ai regardé mais je n'en trouve pas avec la même question, juste des questions similaires pour OSX, ce qui n'est pas ce que nous utilisons.

Merci, pxb

Mise à jour:je viens de faire quelques tests supplémentaires avec les résultats suivants:

  • si je fais une construction 64 bits en utilisant gcc 4.1.2 sur une boîte RHEL5.4 (avec -L/usr/lib64 et -lstdc++ -lrt) et que je l'exécute sur une installation 64 bits de RHEL5, cela fonctionne bien
  • si je fais une construction 32 bits en utilisant gcc 4.1.2 sur une boîte RHEL5.1 (avec -L/usr/lib et -lstdc++ -lrt) et que je l'exécute sur une boîte RHEL5 64 bits exactement la même, nous obtenons des erreurs ENOSYS de sem_timedwait

Il semble donc y avoir une différence entre les bibliothèques d'exécution 64 et 32 ​​bits sur RHEL5.4 (et apparemment RHEL5.3).La seule autre différence était que les versions 32 et 64 bits étaient respectivement réalisées à partir de boîtiers RHEL5.1 et RHEL5.4.

Était-ce utile?

La solution

J'ai enfin découvert quel est le problème.Sur RHEL 5.4, si nous appelons sem_init puis faisons sem_timedwait, nous obtenons un comportement quelque peu aléatoire de l'attente chronométrée, selon l'endroit où se trouve le code, si l'objet qui possède le sem_t est sur le tas ou la pile, etc.Parfois l'attente chronométrée revient immédiatement avec errno = 38 (ENOSYS), parfois elle attend correctement avant de revenir.

L'exécuter via valgrind donne cette erreur :

==32459== Thread 2:
==32459== Syscall param futex(op) contains uninitialised byte(s)
==32459==    at 0x406C78: sem_timedwait (in /lib/libpthread-2.5.so)
==32459==    by 0x8049F2E: TestThread::Run() (in /home/stsadm/semaphore_test/semaphore_test)
==32459==    by 0x44B2307: nxThread::_ThreadProc(void*) (in /home/stsadm/semaphore_test/libcore.so)
==32459==    by 0x4005AA: start_thread (in /lib/libpthread-2.5.so)
==32459==    by 0x355CFD: clone (in /lib/libc-2.5.so)

Si j'exécute exactement le même code sur RHEL 5.2, le problème disparaît et valgrind ne signale aucune erreur.

Si je fais un memset sur la variable sem_t avant d'appeler sem_init, le problème disparaît sur RHEL 5.4

memset( &_semaphore, 0, sizeof( sem_t ) );

Il semble donc qu'un bug ait été introduit avec les sémaphores sur RHEL5.4 ou quelque chose qu'il utilise en interne, et sem_init n'initialise pas correctement la mémoire sem_t.Ou bien, sem_timed wait a changé pour être sensible à cela d'une manière qui ne l'était pas auparavant.

Fait intéressant, en aucun cas sem_init ne renvoie une erreur pour indiquer que cela n'a pas fonctionné.

Alternativement, si le comportement attendu est que sem_init n'initialise pas la mémoire de sem_t et que cela dépend de l'appelant, alors le comportement a certainement changé avec RHEL 5.4.

pxb

Mise à jour - voici le code du scénario de test au cas où quelqu'un d'autre voudrait l'essayer.Notez que le problème ne se produit que lorsque sem_timedwait est appelé à partir d'un .so, et uniquement RHEL5.4 (peut-être que 5.3 ne l'a pas testé), et uniquement lorsqu'il est construit en tant que binaire 32 bits (liaison avec des bibliothèques 32 bits bien sûr)

1) dans semtest.cpp

#include <semaphore.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>

void semtest( int semnum, bool initmem )
{
        sem_t sem;

        if ( initmem )
        {
                memset( &sem, 0, sizeof( sem_t ) );
                printf( "sem %d: memset size = %d\n", semnum, sizeof( sem_t ) );
        }

        errno = 0;
        int res = sem_init( &sem, 0, 0 );

        printf( "sem %d: sem_init res = %d, errno = %d\n", semnum, res, errno );

        timespec ts;
        clock_gettime( CLOCK_REALTIME, &ts );
        ts.tv_sec += 1;

        errno = 0;
        res = sem_timedwait( &sem, &ts );

        printf( "sem %d: sem_timedwait res = %d, errno = %d\n\n", semnum, res, errno );
}

2) dans main.cpp (notez la fonction de test en double afin que nous puissions comparer l'exécution à partir du .so avec dans l'exe)

#include <semaphore.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h>

extern void semtest( int semnum, bool initmem );

void semtest_in_exe( int semnum, bool initmem )
{
        sem_t sem;

        if ( initmem )
        {
                memset( &sem, 0, sizeof( sem_t ) );
                printf( "sem %d: memset size = %d\n", semnum, sizeof( sem_t ) );
        }

        errno = 0;
        int res = sem_init( &sem, 0, 0 );

        printf( "sem %d: sem_init res = %d, errno = %d\n", semnum, res, errno );

        timespec ts;
        clock_gettime( CLOCK_REALTIME, &ts );
        ts.tv_sec += 1;

        errno = 0;
        res = sem_timedwait( &sem, &ts );

        printf( "sem %d: sem_timedwait res = %d, errno = %d\n\n", semnum, res, errno );
}

int main(int argc, char* argv[], char** envp)
{
        semtest( 1, false );
        semtest( 2, true );
        semtest_in_exe( 3, false );
        semtest_in_exe( 4, true );
}

3) voici le Makefile

all: main

semtest.o: semtest.cpp
        gcc -c -fpic -m32 -I /usr/include/c++/4.1.2 -I /usr/include/c++/4.1.2/i386-redhat-linux semtest.cpp -o semtest.o

libsemtest.so: semtest.o
        gcc -shared -m32 -fpic -lstdc++ -lrt semtest.o -o libsemtest.so

main: libsemtest.so
        gcc -m32 -L . -lsemtest main.cpp -o semtest

Les cas de tests sont :

  1. exécuter de l'intérieur .donc sans faire de memset
  2. exécuter depuis l'intérieur de .so et faire memset
  3. exécuter à partir d'exe sans faire de memset
  4. exécuter à partir d'exe et faire memset

Et voici le résultat exécuté sur RHEL5.4

sem 1: sem_init res = 0, errno = 0
sem 1: sem_timedwait res = -1, errno = 38

sem 2: memset size = 16
sem 2: sem_init res = 0, errno = 0
sem 2: sem_timedwait res = -1, errno = 110

sem 3: sem_init res = 0, errno = 0
sem 3: sem_timedwait res = -1, errno = 110

sem 4: memset size = 16
sem 4: sem_init res = 0, errno = 0
sem 4: sem_timedwait res = -1, errno = 110

Vous pouvez voir que le cas 1 revient immédiatement avec errno = 38.

Si nous exécutons exactement le même code sur RHEL5.2, nous obtenons ce qui suit :

sem 1: sem_init res = 0, errno = 0
sem 1: sem_timedwait res = -1, errno = 110

sem 2: memset size = 16
sem 2: sem_init res = 0, errno = 0
sem 2: sem_timedwait res = -1, errno = 110

sem 3: sem_init res = 0, errno = 0
sem 3: sem_timedwait res = -1, errno = 110

sem 4: memset size = 16
sem 4: sem_init res = 0, errno = 0
sem 4: sem_timedwait res = -1, errno = 110

Vous pouvez voir que tous les cas fonctionnent désormais comme prévu !

Autres conseils

Il paraît que semtest appelle sem_init@GLIBC_2.1, et libsemtest.so appelle sem_init@GLIBC_2.0.

sem_timedwait() semble nécessiter la version 2.1.

J'ai obtenu des résultats corrects pour les quatre tests en ajoutant -lpthread à la règle qui crée libsemtest.so.

J'ai testé cela sur RH 5.3.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top