Наконец-то выяснилось, в чем проблема. В RHEL 5.4, если мы будем называть sem_init, а затем sem_timedwait, мы получим несколько случайное поведение времени ожидания, в зависимости от того, где находится код, независимо от того, принадлежит ли объект sem_t к куче или стеку и т. Д. Иногда время ожидания возвращается немедленно с errno = 38 (ENOSYS), иногда он корректно ждет, прежде чем вернуться.
Запуск его через Valgrind дает эту ошибку:
==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)
Если я бегу точно такой же код на RHEL 5.2 проблема не уходит, и Valgrind сообщения без ошибок.
Если я делаю MemSet на sem_t переменного перед вызовом sem_init проблема уходит на RHEL 5,4
memset(&_semaphore, 0, sizeof(sem_t));
Итак, это выглядит как ошибка была введена с семафорами на RHEL5.4 или что-то, что это использует внутренне, а sem_init неправильно инициализирует память sem_t. Или, sem_timed wait изменился, чтобы быть чувствительным к этому так, как раньше.
Интересно, что ни в коем случае sem_init не возвращает ошибку, чтобы указать, что она не работает.
В качестве альтернативы, если ожидаемое поведение является то, что sem_init не intialise памяти sem_t и это до абонента, то поведение, конечно, изменилось с RHEL 5.4
pxb
Update - вот в случае, если кто-то еще захочет попробовать его. Обратите внимание, что проблема возникает только в том случае, когда sem_timedwait вызывается из .so, и только RHEL5.4 (может быть, 5.3 не тестировал ее), и только тогда, когда он был построен как 32-битный двоичный файл (привязка к 32-разрядным библиотекам, конечно)
1) в 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) в main.cpp (обратите внимание на повторяющиеся функции тестирования, поэтому мы можем сравнить работает внутри .so с в ехе)
#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) вот 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
Тестовые являются:
- бежать внутри .so, не делая MemSet
- бежать изнутри .so и сделать MemSet
- бежать изнутри ехе, не делая MemSet
- бежать из в ехе и не MemSet
и вот результат работает на 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
Вы можете видеть, что случай 1 возвращается немедленно егто = 38.
Если мы запустим тот же самый код на RHEL5.2 мы получаем следующее:
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
Вы можете видеть, что все дела теперь работают так, как ожидалось!
Удалось исправить это, но я не знаю, как работает исправление. Код, вызывающий функции семафора, был в классе внутри .so, и они, в свою очередь, вызывались из самого исполняемого файла. Если мы переместим код из файла cpp в заголовок (т. Е. Эффективно введем класс в исполняемый файл), проблема исчезнет. так, похоже, это: на RHEL5.4, если мы вызываем sem_timedwait из .so, он терпит неудачу, но если мы делаем тот же самый вызов из исполняемого файла, он работает. И я понятия не имею, почему ... – pxb