summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
authorHaru <haru@dotalux.com>2013-10-11 05:07:45 +0200
committerHaru <haru@dotalux.com>2013-10-26 12:46:46 +0200
commit44c33fda3614d588e6bf6cee1cf884e98f1531f0 (patch)
treeb617c00c97675668f3c3a8a44b4c966e39ed520c /src/common
parentd39918017d4416add066fb78ab7f23cb4436c614 (diff)
downloadhercules-44c33fda3614d588e6bf6cee1cf884e98f1531f0.tar.gz
hercules-44c33fda3614d588e6bf6cee1cf884e98f1531f0.tar.bz2
hercules-44c33fda3614d588e6bf6cee1cf884e98f1531f0.tar.xz
hercules-44c33fda3614d588e6bf6cee1cf884e98f1531f0.zip
Changed 'tick' variables to 64 bit
- This fixes an issue with timers that stop working after about 24-49 days when the tick overflows (note that this may happen much earlier than that, and at hard to predict times, on some systems) - Updated the RDTSC help message in the configure script to also warn users about issues with SpeedStep enabled systems. - On Windows, tick() still has a resolution of 10~15ms (or even as low as 100ms on some systems). A TODO comment (thanks, Ai4rei) was added for a follow-up patch, as I want this one to be as small as possible) - Note: on Windows versions earlier than 6.x (Vista, Server 2008), the tick overflow issue is NOT fixed, since they don't support the function used to retrieve a 64 bit tick. This isn't a big issue, since those platforms are already - or going soon to be - out of their extended support period, and it's already advisable to upgrade, for other reasons. If you're the unfortunate user of such a system, it is recommended that you reboot your machine at least once every 49 days for Hercules to work reliably. - Note: To clear some doubts, since I've already been asked, this has absolutely NOTHING to do with 32/64 bit CPUs or OSes. It's all about a variable's size, not the size of registers of your CPU, and your 32bit CPU will be able to handle this just fine. Signed-off-by: Haru <haru@dotalux.com>
Diffstat (limited to 'src/common')
-rw-r--r--src/common/console.c2
-rw-r--r--src/common/console.h2
-rw-r--r--src/common/random.c12
-rw-r--r--src/common/socket.c5
-rw-r--r--src/common/socket.h3
-rw-r--r--src/common/sql.c2
-rw-r--r--src/common/timer.c86
-rw-r--r--src/common/timer.h21
8 files changed, 85 insertions, 48 deletions
diff --git a/src/common/console.c b/src/common/console.c
index b25de84b3..cb8ed5917 100644
--- a/src/common/console.c
+++ b/src/common/console.c
@@ -344,7 +344,7 @@ void *cThread_main(void *x) {
return NULL;
}
-int console_parse_timer(int tid, unsigned int tick, int id, intptr_t data) {
+int console_parse_timer(int tid, int64 tick, int id, intptr_t data) {
int i;
EnterSpinLock(&console->ptlock);
for(i = 0; i < cinput.count; i++) {
diff --git a/src/common/console.h b/src/common/console.h
index cef898f17..1beed964a 100644
--- a/src/common/console.h
+++ b/src/common/console.h
@@ -56,7 +56,7 @@ struct console_interface {
/* */
void (*parse_init) (void);
void (*parse_final) (void);
- int (*parse_timer) (int tid, unsigned int tick, int id, intptr_t data);
+ int (*parse_timer) (int tid, int64 tick, int id, intptr_t data);
void *(*pthread_main) (void *x);
void (*parse) (char* line);
void (*parse_sub) (char* line);
diff --git a/src/common/random.c b/src/common/random.c
index 2f1b62934..e46c52cad 100644
--- a/src/common/random.c
+++ b/src/common/random.c
@@ -17,17 +17,17 @@
/// Initializes the random number generator with an appropriate seed.
void rnd_init(void)
{
- uint32 seed = timer->gettick();
- seed += (uint32)time(NULL);
+ unsigned long seed = (unsigned long)timer->gettick();
+ seed += (unsigned long)time(NULL);
#if defined(WIN32)
- seed += GetCurrentProcessId();
- seed += GetCurrentThreadId();
+ seed += (unsigned long)GetCurrentProcessId();
+ seed += (unsigned long)GetCurrentThreadId();
#else
#if defined(HAVE_GETPID)
- seed += (uint32)getpid();
+ seed += (unsigned long)getpid();
#endif // HAVE_GETPID
#if defined(HAVE_GETTID)
- seed += (uint32)gettid();
+ seed += (unsigned long)gettid();
#endif // HAVE_GETTID
#endif
init_genrand(seed);
diff --git a/src/common/socket.c b/src/common/socket.c
index 7c8b3738b..c66153550 100644
--- a/src/common/socket.c
+++ b/src/common/socket.c
@@ -896,7 +896,7 @@ int do_sockets(int next)
typedef struct _connect_history {
struct _connect_history* next;
uint32 ip;
- uint32 tick;
+ int64 tick;
int count;
unsigned ddos : 1;
} ConnectHistory;
@@ -1043,8 +1043,7 @@ static int connect_check_(uint32 ip)
/// Timer function.
/// Deletes old connection history records.
-static int connect_check_clear(int tid, unsigned int tick, int id, intptr_t data)
-{
+static int connect_check_clear(int tid, int64 tick, int id, intptr_t data) {
int i;
int clear = 0;
int list = 0;
diff --git a/src/common/socket.h b/src/common/socket.h
index 0e34da660..923fa2515 100644
--- a/src/common/socket.h
+++ b/src/common/socket.h
@@ -77,8 +77,7 @@ typedef int (*RecvFunc)(int fd);
typedef int (*SendFunc)(int fd);
typedef int (*ParseFunc)(int fd);
-struct socket_data
-{
+struct socket_data {
struct {
unsigned char eof : 1;
unsigned char server : 1;
diff --git a/src/common/sql.c b/src/common/sql.c
index 9b7fe4108..dc6c4c569 100644
--- a/src/common/sql.c
+++ b/src/common/sql.c
@@ -180,7 +180,7 @@ int Sql_Ping(Sql* self)
/// Wrapper function for Sql_Ping.
///
/// @private
-static int Sql_P_KeepaliveTimer(int tid, unsigned int tick, int id, intptr_t data)
+static int Sql_P_KeepaliveTimer(int tid, int64 tick, int id, intptr_t data)
{
Sql* self = (Sql*)data;
ShowInfo("Pinging SQL server to keep connection alive...\n");
diff --git a/src/common/timer.c b/src/common/timer.c
index a2378a5aa..ccd91f9c7 100644
--- a/src/common/timer.c
+++ b/src/common/timer.c
@@ -65,8 +65,7 @@ struct timer_func_list {
} *tfl_root = NULL;
/// Sets the name of a timer function.
-int timer_add_func_list(TimerFunc func, char* name)
-{
+int timer_add_func_list(TimerFunc func, char* name) {
struct timer_func_list* tfl;
if (name) {
@@ -139,22 +138,62 @@ static void rdtsc_calibrate(){
#endif
-/// platform-abstracted tick retrieval
-static unsigned int tick(void) {
+/**
+ * platform-abstracted tick retrieval
+ * @return server's current tick
+ */
+static int64 tick(void) {
#if defined(WIN32)
- return GetTickCount();
+ // Windows: GetTickCount/GetTickCount64: Return the number of
+ // milliseconds that have elapsed since the system was started.
+
+ // TODO: GetTickCount/GetTickCount64 has a resolution of only 10~15ms.
+ // Ai4rei recommends that we replace it with either performance
+ // counters or multimedia timers if we want it to be more accurate.
+ // I'm leaving this for a future follow-up patch.
+
+ // GetTickCount64 is only available in Windows Vista / Windows Server
+ // 2008 or newer. Since we still support older versions, this runtime
+ // check is required in order not to crash.
+ // http://msdn.microsoft.com/en-us/library/windows/desktop/ms724411%28v=vs.85%29.aspx
+ static bool first = true;
+ static ULONGLONG (WINAPI *pGetTickCount64)(void) = NULL;
+
+ if( first ) {
+ HMODULE hlib = GetModuleHandle(TEXT("KERNEL32.DLL"));
+ if( hlib != NULL )
+ pGetTickCount64 = (ULONGLONG (WINAPI *)(void))GetProcAddress(hlib, "GetTickCount64");
+ first = false;
+ }
+ if (pGetTickCount64)
+ return (int64)pGetTickCount64();
+ // 32-bit fallback. Note: This will wrap around every ~49 days since system startup!!!
+ return (int64)GetTickCount();
#elif defined(ENABLE_RDTSC)
- //
- return (unsigned int)((_rdtsc() - RDTSC_BEGINTICK) / RDTSC_CLOCK);
- //
+ // RDTSC: Returns the number of CPU cycles since reset. Unreliable if
+ // the CPU frequency is variable.
+ return (int64)((_rdtsc() - RDTSC_BEGINTICK) / RDTSC_CLOCK);
#elif defined(HAVE_MONOTONIC_CLOCK)
+ // Monotinic clock: Implementation-defined.
+ // Clock that cannot be set and represents monotonic time since some
+ // unspecified starting point. This clock is not affected by
+ // discontin‐uous jumps in the system time (e.g., if the system
+ // administrator manually changes the clock), but is affected by
+ // the incremental adjustments performed by adjtime(3) and NTP.
struct timespec tval;
clock_gettime(CLOCK_MONOTONIC, &tval);
- return tval.tv_sec * 1000 + tval.tv_nsec / 1000000;
+ // int64 cast to avoid overflows on platforms where time_t is 32 bit
+ return (int64)tval.tv_sec * 1000 + tval.tv_nsec / 1000000;
#else
+ // Fallback, regular clock: Number of milliseconds since epoch.
+ // The time returned by gettimeofday() is affected by discontinuous
+ // jumps in the system time (e.g., if the system administrator
+ // manually changes the system time). If you need a monotonically
+ // increasing clock, see clock_gettime(2).
struct timeval tval;
gettimeofday(&tval, NULL);
- return tval.tv_sec * 1000 + tval.tv_usec / 1000;
+ // int64 cast to avoid overflows on platforms where time_t is 32 bit
+ return (int64)tval.tv_sec * 1000 + tval.tv_usec / 1000;
#endif
}
@@ -162,28 +201,28 @@ static unsigned int tick(void) {
#if defined(TICK_CACHE) && TICK_CACHE > 1
//////////////////////////////////////////////////////////////////////////
// tick is cached for TICK_CACHE calls
-static unsigned int gettick_cache;
+static int64 gettick_cache;
static int gettick_count = 1;
-unsigned int timer_gettick_nocache(void) {
+int64 timer_gettick_nocache(void) {
gettick_count = TICK_CACHE;
gettick_cache = tick();
return gettick_cache;
}
-unsigned int timer_gettick(void) {
+int64 timer_gettick(void) {
return ( --gettick_count == 0 ) ? gettick_nocache() : gettick_cache;
}
//////////////////////////////
#else
//////////////////////////////
// tick doesn't get cached
-unsigned int timer_gettick_nocache(void)
+int64 timer_gettick_nocache(void)
{
return tick();
}
-unsigned int timer_gettick(void) {
+int64 timer_gettick(void) {
return tick();
}
//////////////////////////////////////////////////////////////////////////
@@ -237,7 +276,7 @@ static int acquire_timer(void) {
/// Starts a new timer that is deleted once it expires (single-use).
/// Returns the timer's id.
-int timer_add(unsigned int tick, TimerFunc func, int id, intptr_t data) {
+int timer_add(int64 tick, TimerFunc func, int id, intptr_t data) {
int tid;
tid = acquire_timer();
@@ -254,12 +293,11 @@ int timer_add(unsigned int tick, TimerFunc func, int id, intptr_t data) {
/// Starts a new timer that automatically restarts itself (infinite loop until manually removed).
/// Returns the timer's id, or INVALID_TIMER if it fails.
-int timer_add_interval(unsigned int tick, TimerFunc func, int id, intptr_t data, int interval)
-{
+int timer_add_interval(int64 tick, TimerFunc func, int id, intptr_t data, int interval) {
int tid;
if( interval < 1 ) {
- ShowError("timer_add_interval: invalid interval (tick=%u %p[%s] id=%d data=%d diff_tick=%d)\n", tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, timer->gettick()));
+ ShowError("timer_add_interval: invalid interval (tick=%"PRId64" %p[%s] id=%d data=%d diff_tick=%"PRId64")\n", tick, func, search_timer_func_list(func), id, data, DIFF_TICK(tick, timer->gettick()));
return INVALID_TIMER;
}
@@ -301,13 +339,13 @@ int timer_do_delete(int tid, TimerFunc func) {
/// Adjusts a timer's expiration time.
/// Returns the new tick value, or -1 if it fails.
-int timer_addtick(int tid, unsigned int tick) {
+int64 timer_addtick(int tid, int64 tick) {
return timer->settick(tid, timer_data[tid].tick+tick);
}
/// Modifies a timer's expiration time (an alternative to deleting a timer and starting a new one).
/// Returns the new tick value, or -1 if it fails.
-int timer_settick(int tid, unsigned int tick) {
+int64 timer_settick(int tid, int64 tick) {
size_t i;
// search timer position
@@ -332,8 +370,8 @@ int timer_settick(int tid, unsigned int tick) {
/// Executes all expired timers.
/// Returns the value of the smallest non-expired timer (or 1 second if there aren't any).
-int do_timer(unsigned int tick) {
- int diff = TIMER_MAX_INTERVAL; // return value
+int do_timer(int64 tick) {
+ int64 diff = TIMER_MAX_INTERVAL; // return value
// process all timers one by one
while( BHEAP_LENGTH(timer_heap) ) {
@@ -381,7 +419,7 @@ int do_timer(unsigned int tick) {
}
}
- return cap_value(diff, TIMER_MIN_INTERVAL, TIMER_MAX_INTERVAL);
+ return (int)cap_value(diff, TIMER_MIN_INTERVAL, TIMER_MAX_INTERVAL);
}
unsigned long timer_get_uptime(void) {
diff --git a/src/common/timer.h b/src/common/timer.h
index 600f9fd02..4a2bebe7d 100644
--- a/src/common/timer.h
+++ b/src/common/timer.h
@@ -5,7 +5,8 @@
#define _TIMER_H_
#include "../common/cbasetypes.h"
-#define DIFF_TICK(a,b) ((int)((a)-(b)))
+#define DIFF_TICK(a,b) ((a)-(b))
+#define DIFF_TICK32(a,b) ((int32)((a)-(b)))
#define INVALID_TIMER -1
@@ -18,10 +19,10 @@ enum {
// Struct declaration
-typedef int (*TimerFunc)(int tid, unsigned int tick, int id, intptr_t data);
+typedef int (*TimerFunc)(int tid, int64 tick, int id, intptr_t data);
struct TimerData {
- unsigned int tick;
+ int64 tick;
TimerFunc func;
unsigned char type;
int interval;
@@ -40,22 +41,22 @@ struct TimerData {
struct timer_interface {
/* funcs */
- unsigned int (*gettick) (void);
- unsigned int (*gettick_nocache) (void);
+ int64 (*gettick) (void);
+ int64 (*gettick_nocache) (void);
- int (*add) (unsigned int tick, TimerFunc func, int id, intptr_t data);
- int (*add_interval) (unsigned int tick, TimerFunc func, int id, intptr_t data, int interval);
+ int (*add) (int64 tick, TimerFunc func, int id, intptr_t data);
+ int (*add_interval) (int64 tick, TimerFunc func, int id, intptr_t data, int interval);
const struct TimerData *(*get) (int tid);
int (*delete) (int tid, TimerFunc func);
- int (*addtick) (int tid, unsigned int tick);
- int (*settick) (int tid, unsigned int tick);
+ int64 (*addtick) (int tid, int64 tick);
+ int64 (*settick) (int tid, int64 tick);
int (*add_func_list) (TimerFunc func, char* name);
unsigned long (*get_uptime) (void);
- int (*do_timer) (unsigned int tick);
+ int (*do_timer) (int64 tick);
void (*init) (void);
void (*final) (void);
};