Skip to content

Commit

Permalink
Added a fix for old game that use sem_timewait in an incorrect way
Browse files Browse the repository at this point in the history
  • Loading branch information
ptitSeb committed Oct 8, 2024
1 parent 62bc6bb commit c65c514
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/wrapped/generated/functions_list.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3660,6 +3660,7 @@ wrappedlibpthread:
- pthread_mutex_timedlock
- pthread_once
- pthread_setname_np
- sem_timedwait
- vFppp:
- _pthread_cleanup_push
- _pthread_cleanup_push_defer
Expand Down
1 change: 1 addition & 0 deletions src/wrapped/generated/wrappedlibpthreadtypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ typedef int32_t (*iFpppp_t)(void*, void*, void*, void*);
GO(pthread_mutex_timedlock, iFpp_t) \
GO(pthread_once, iFpp_t) \
GO(pthread_setname_np, iFpp_t) \
GO(sem_timedwait, iFpp_t) \
GO(_pthread_cleanup_push, vFppp_t) \
GO(_pthread_cleanup_push_defer, vFppp_t) \
GO(pthread_setaffinity_np, iFLup_t) \
Expand Down
22 changes: 22 additions & 0 deletions src/wrapped/wrappedlibpthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <dlfcn.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>

#include "wrappedlibs.h"

Expand Down Expand Up @@ -132,6 +133,27 @@ EXPORT void my___pthread_initialize()
// nothing, the lib initialize itself now
}

void Timespec2Timespec64(void* dest, const void* source);
EXPORT int my_sem_timedwait(sem_t* sem, struct timespec * t)
{
// some x86 game are not computing timeout correctly (ex: Anomaly Warzone Earth linux version)
#ifdef __USE_TIME64_REDIRECTS
struct timespec t1;
Timespec2Timespec64(&t1, t);
while(t1.tv_nsec>=1000000000) {
t1.tv_nsec-=1000000000;
t1.tv_sec+=1;
}
return sem_timedwait(sem, &t1);
#else
while(t->tv_nsec>=1000000000) {
t->tv_nsec-=1000000000;
t->tv_sec+=1;
}
return sem_timedwait(sem, t);
#endif
}

#define PRE_INIT\
if(1) \
lib->w.lib = dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL); \
Expand Down
2 changes: 1 addition & 1 deletion src/wrapped/wrappedlibpthread_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ GO(sem_getvalue, iFpp)
GO(sem_init, iFpiu)
GO(sem_open, pFpOM)
GO(sem_post, iFp)
GO(sem_timedwait, iFpp)
GOM(sem_timedwait, iFpp) //%noE
GO(sem_trywait, iFp)
GO(sem_unlink, iFp)
GO(sem_wait, iFp)
Expand Down

5 comments on commit c65c514

@M-HT
Copy link
Contributor

@M-HT M-HT commented on c65c514 Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function sem_timedwait is defined as:
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);
The second parameter is const so you shoudn't be modifying it (when __USE_TIME64_REDIRECTS is not defined).

@ptitSeb
Copy link
Owner Author

@ptitSeb ptitSeb commented on c65c514 Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree, but I don't see a case were that parameter is in a RO section, as it needs to be dynamic. Also, the function is just there to make the settings correct. Technicaly, it's the same timespec. It's done like that to avoid a copy in the likely case the timespec is correctly formed.
Did you see any issue with that hack that would require the use of a temporary timespec value?

@M-HT
Copy link
Contributor

@M-HT M-HT commented on c65c514 Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't seen any issue with the hack, but the calling program might be using the parameter after the call and making (reasonable) assumption that the function doesn't change the value.
If you want to avoid a copy, you could do something like this:

    if(t->tv_nsec>=1000000000) {
        struct timespec t1;
        t1.tv_sec=t->tv_sec+1;
        t1.tv_nsec=t->tv_nsec-1000000000;
        while(t1.tv_nsec>=1000000000) {
            t1.tv_nsec-=1000000000;
            t1.tv_sec+=1;
        }        
        return sem_timedwait(sem, &t1);
    }
    return sem_timedwait(sem, t);

@ptitSeb
Copy link
Owner Author

@ptitSeb ptitSeb commented on c65c514 Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I can do that.

@ptitSeb
Copy link
Owner Author

@ptitSeb ptitSeb commented on c65c514 Oct 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, done with 7b8a6aa

Please sign in to comment.