It didn't seem to be caused by a race condition (if it worked/didn't work, it would consistently work/not work until you made a change to the code, but after you made that change, the original binary would start behaving differently) so I figured it had to involve uninitialized memory being involved somehow. I kept checking over and over that I was initializing everything, even disassembling my code to make sure the compiler wasn't miscompiling my initialization code. I eventually added logging around the semaphore initialization. When that didn't help, I added even more paranoid logging. It looked like this:
Code: Select all
npvr_scene_buffer_t * npvr_sb_create(const npvr_pass_t *passes, int pass_count, int width_tiles, int height_tiles) {
int p, l;
assert(width_tiles <= 40);
assert(width_tiles > 0);
assert(height_tiles <= 15);
assert(height_tiles > 0);
assert(pass_count > 0);
assert(passes != NULL);
npvr_scene_buffer_t * sb = malloc(sizeof(npvr_scene_buffer_t));
npvr_pass_internal_t * intpasses = calloc(pass_count, sizeof(npvr_pass_internal_t));
assert(sb != NULL);
assert(intpasses != NULL);
NPVR_LOG("npvr_sb_create:\n");
NPVR_LOG(" SB: %p\n", sb);
sb->passes = intpasses;
sb->pass_count = pass_count;
sb->width_tiles = width_tiles;
sb->height_tiles = height_tiles;
NPVR_LOG(" PreBanks available: %i\n", sem_count(&sb->banks_available));
NPVR_LOG(" PreBanks available: 0x%08x\n", sem_count(&sb->banks_available));
NPVR_LOG(" PreBanks available init: %i\n", sb->banks_available.initialized);
errno = 0;
int ret = sem_init(&sb->banks_available, 2);
int semerrno = errno;
if (ret)
NPVR_LOG(" ****sem_init ERROR****\n");
NPVR_LOG(" PostErrno: %i\n", semerrno);
NPVR_LOG(" PostBanks available: %i\n", sem_count(&sb->banks_available));
NPVR_LOG(" PostBanks available: 0x%08x\n", sem_count(&sb->banks_available));
NPVR_LOG(" Banks available init: %i\n", sb->banks_available.initialized);
//The rest is unimportant for this
Code: Select all
npvr_sb_create:
SB: 0x8c12f4a0
PreBanks available: 757101421
PreBanks available: 0x2d20736d
PreBanks available init: 540618798
PostErrno: 0
PostBanks available: 2
PostBanks available: 0x00000002
Banks available init: 1
npvr_sb_create:
SB: 0x8c12f528
PreBanks available: -42008063
PreBanks available: 0xfd7f0201
PreBanks available init: 33292289
****sem_init ERROR****
PostErrno: 22
PostBanks available: -42008063
PostBanks available: 0xfd7f0201
Banks available init: 33292289
npvr_sb_create:
SB: 0x8c12f5b0
PreBanks available: 537539104
PreBanks available: 0x200a3220
PreBanks available init: 979725410
PostErrno: 0
PostBanks available: 2
PostBanks available: 0x00000002
Banks available init: 1
Code: Select all
int sem_init(semaphore_t *sm, int count) {
if(sm->count < 0) {
errno = EINVAL;
return -1;
}
sm->count = count;
sm->initialized = 1;
return 0;
}
Code: Select all
if(sm->count < 0) {
Code: Select all
if(count < 0) {
If you want to be extra careful, it might be worth setting sm->initialized to zero, to make it more clear that the semaphore was not initialized correctly to people who don't check the return value of sem_init:
Code: Select all
int sem_init(semaphore_t *sm, int count) {
if(count < 0) {
errno = EINVAL;
sm->initialized = 0; /* Mark semaphore as invalid! */
return -1;
}
sm->count = count;
sm->initialized = 1;
return 0;
}