Cuối cùng đã tìm ra vấn đề là gì. Trên RHEL 5.4 nếu chúng ta gọi sem_init thì làm sem_timedwait chúng ta nhận được hành vi ngẫu nhiên của thời gian chờ, tùy thuộc vào vị trí mã, cho dù đối tượng sở hữu sem_t là trên heap hay stack, vv Đôi khi thời gian chờ đợi trả về ngay lập tức với errno = 38 (ENOSYS), đôi khi nó chờ đợi chính xác trước khi trở về.
Chạy nó qua valgrind cho lỗi này:
==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)
Nếu tôi chạy chính xác cùng mã trên RHEL 5.2 vấn đề đi xa và valgrind báo cáo không có lỗi.
Nếu tôi làm một memset trên biến sem_t trước khi gọi sem_init vấn đề đi xa trên RHEL 5,4
memset(&_semaphore, 0, sizeof(sem_t));
Vì vậy, nó trông giống như một lỗi đã được giới thiệu với Cột trên RHEL5.4 hoặc cái gì đó nó sử dụng nội bộ và sem_init không khởi tạo chính xác bộ nhớ sem_t. Hoặc, sem_timed wait đã thay đổi để nhạy cảm với điều này theo cách trước đây.
Điều thú vị là không có trường hợp nào sem_init trả lại lỗi để cho biết lỗi đó không hoạt động.
Ngoài ra, nếu hành vi dự kiến là sem_init sẽ không intialise ký ức của sem_t và đó là lên đến người gọi, sau đó hành vi đã chắc chắn thay đổi với RHEL 5.4
pxb
Update - đây là kiểm tra mã trường hợp trong trường hợp bất cứ ai khác muốn thử nó. Lưu ý vấn đề chỉ xảy ra khi sem_timedwait được gọi từ một .so, và chỉ RHEL5.4 (có thể 5.3 chưa thử nghiệm), và chỉ khi được xây dựng dưới dạng nhị phân 32 bit (liên kết với 32 bit libs của khóa học)
1) trong 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) trong main.cpp (chú ý chức năng kiểm tra trùng lặp vì vậy chúng tôi có thể so sánh chạy từ bên trong .so với trong 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) đây là 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
Các trường hợp kiểm tra là:
- chạy từ bên trong mà không làm .so memset
- chạy từ bên trong .so và làm memset
- chạy từ bên trong exe mà không làm memset
- chạy từ bên trong exe và làm memset
Và đây là kết quả chạy trên 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
Bạn có thể thấy trường hợp đó 1 lợi nhuận ngay lập tức với errno = 38.
Nếu chúng ta chạy các mã chính xác như nhau trên RHEL5.2 chúng tôi nhận được như sau:
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
Bạn có thể thấy rằng tất cả các trường hợp giờ đây hoạt động như mong đợi!
Được quản lý để khắc phục sự cố, nhưng tôi không chắc chắn tại sao bản sửa lỗi hoạt động. Mã gọi các hàm semaphore nằm trong một lớp bên trong một .so, và chúng lần lượt được gọi từ chính tệp thực thi. Nếu chúng tôi di chuyển mã từ tệp cpp sang tiêu đề (ví dụ: hiệu chỉnh nội tuyến lớp vào tệp thi hành) thì sự cố sẽ biến mất. vì vậy, nó có vẻ như thế này: trên RHEL5.4 nếu chúng ta gọi sem_timedwait từ bên trong .so nó không thành công, nhưng nếu chúng ta thực hiện cùng một cuộc gọi từ tệp thực thi nó hoạt động. Và tôi không biết tại sao ... – pxb