diff --git a/contrib/pgcrypto/fortuna.c b/contrib/pgcrypto/fortuna.c index 5028203..1654c41 100644 --- a/contrib/pgcrypto/fortuna.c +++ b/contrib/pgcrypto/fortuna.c @@ -31,7 +31,6 @@ #include "postgres.h" -#include #include #include "px.h" @@ -89,8 +88,8 @@ */ #define NUM_POOLS 23 -/* in microseconds */ -#define RESEED_INTERVAL 100000 /* 0.1 sec */ +/* in nanoseconds */ +#define RESEED_INTERVAL 100000000 /* 0.1 sec */ /* for one big request, reseed after this many bytes */ #define RESEED_BYTES (1024*1024) @@ -123,7 +122,7 @@ struct fortuna_state MD_CTX pool[NUM_POOLS]; CIPH_CTX ciph; unsigned reseed_count; - struct timeval last_reseed_time; + struct timespec last_reseed_time; unsigned pool0_bytes; unsigned rnd_pos; int tricks_done; @@ -223,10 +222,10 @@ static int enough_time_passed(FState *st) { int ok; - struct timeval tv; - struct timeval *last = &st->last_reseed_time; + struct timespec tv; + struct timespec *last = &st->last_reseed_time; - gettimeofday(&tv, NULL); + clock_gettime(CLOCK_REALTIME, &tv); /* check how much time has passed */ ok = 0; @@ -234,10 +233,10 @@ enough_time_passed(FState *st) ok = 1; else if (tv.tv_sec == last->tv_sec + 1) { - if (1000000 + tv.tv_usec - last->tv_usec >= RESEED_INTERVAL) + if (1000000000 + tv.tv_nsec - last->tv_nsec >= RESEED_INTERVAL) ok = 1; } - else if (tv.tv_usec - last->tv_usec >= RESEED_INTERVAL) + else if (tv.tv_nsec - last->tv_nsec >= RESEED_INTERVAL) ok = 1; /* reseed will happen, update last_reseed_time */ diff --git a/contrib/pgcrypto/random.c b/contrib/pgcrypto/random.c index d72679e..34bf40e 100644 --- a/contrib/pgcrypto/random.c +++ b/contrib/pgcrypto/random.c @@ -162,7 +162,6 @@ try_win32_perfc(uint8 *dst) #define TRY_UNIXSTD #include -#include #include #include @@ -178,7 +177,7 @@ try_unix_std(uint8 *dst) pid_t pid; int x; PX_MD *md; - struct timeval tv; + struct timespec tv; int res; /* process id */ @@ -187,7 +186,7 @@ try_unix_std(uint8 *dst) dst += sizeof(pid); /* time */ - gettimeofday(&tv, NULL); + clock_gettime(CLOCK_REALTIME_COARSE, &tv); memcpy(dst, (uint8 *) &tv, sizeof(tv)); dst += sizeof(tv); diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 2189c22..1e57a27 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -4765,24 +4765,24 @@ BootStrapXLOG(void) char *recptr; bool use_existent; uint64 sysidentifier; - struct timeval tv; + struct timespec tv; pg_crc32c crc; /* * Select a hopefully-unique system identifier code for this installation. - * We use the result of gettimeofday(), including the fractional seconds + * We use the result of clock_gettime(), including the fractional seconds * field, as being about as unique as we can easily get. (Think not to * use random(), since it hasn't been seeded and there's no portable way * to seed it other than the system clock value...) The upper half of the * uint64 value is just the tv_sec part, while the lower half contains the - * tv_usec part (which must fit in 20 bits), plus 12 bits from our current + * tv_nsec part (which must fit in 20 bits), plus 12 bits from our current * PID for a little extra uniqueness. A person knowing this encoding can * determine the initialization time of the installation, which could * perhaps be useful sometimes. */ - gettimeofday(&tv, NULL); + clock_gettime(CLOCK_REALTIME_COARSE, &tv); sysidentifier = ((uint64) tv.tv_sec) << 32; - sysidentifier |= ((uint64) tv.tv_usec) << 12; + sysidentifier |= ((uint64) tv.tv_nsec) << 12; sysidentifier |= getpid() & 0xFFF; /* First timeline ID is always 1 */ diff --git a/src/backend/libpq/auth.c b/src/backend/libpq/auth.c index d907e6b..d0652bb 100644 --- a/src/backend/libpq/auth.c +++ b/src/backend/libpq/auth.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include "common/ip.h" @@ -2434,7 +2435,7 @@ CheckRADIUSAuth(Port *port) char portstr[128]; ACCEPT_TYPE_ARG3 addrsize; fd_set fdset; - struct timeval endtime; + struct timespec endtime; int i, j, r; @@ -2622,17 +2623,17 @@ CheckRADIUSAuth(Port *port) * the latch was set would improve the responsiveness to * timeouts/cancellations. */ - gettimeofday(&endtime, NULL); + clock_gettime(CLOCK_REALTIME_COARSE, &endtime); endtime.tv_sec += RADIUS_TIMEOUT; while (true) { struct timeval timeout; - struct timeval now; + struct timespec now; int64 timeoutval; - gettimeofday(&now, NULL); - timeoutval = (endtime.tv_sec * 1000000 + endtime.tv_usec) - (now.tv_sec * 1000000 + now.tv_usec); + clock_gettime(CLOCK_REALTIME, &now); + timeoutval = (endtime.tv_sec * 1000000000 + endtime.tv_nsec) - (now.tv_sec * 1000000000 + now.tv_nsec); if (timeoutval <= 0) { ereport(LOG, @@ -2640,7 +2641,7 @@ CheckRADIUSAuth(Port *port) closesocket(sock); return STATUS_ERROR; } - timeout.tv_sec = timeoutval / 1000000; + timeout.tv_sec = timeoutval / 10000000000; timeout.tv_usec = timeoutval % 1000000; FD_ZERO(&fdset); diff --git a/src/backend/postmaster/autovacuum.c b/src/backend/postmaster/autovacuum.c index 1a92ca1..5b8cee0 100644 --- a/src/backend/postmaster/autovacuum.c +++ b/src/backend/postmaster/autovacuum.c @@ -290,7 +290,7 @@ NON_EXEC_STATIC void AutoVacLauncherMain(int argc, char *argv[]) pg_attribute_no static Oid do_start_worker(void); static void launcher_determine_sleep(bool canlaunch, bool recursing, - struct timeval * nap); + struct timespec * nap); static void launch_worker(TimestampTz now); static List *get_database_list(void); static void rebuild_database_list(Oid newdb); @@ -577,7 +577,7 @@ AutoVacLauncherMain(int argc, char *argv[]) /* loop until shutdown request */ while (!got_SIGTERM) { - struct timeval nap; + struct timespec nap; TimestampTz current_time = 0; bool can_launch; int rc; @@ -598,7 +598,7 @@ AutoVacLauncherMain(int argc, char *argv[]) */ rc = WaitLatch(MyLatch, WL_LATCH_SET | WL_TIMEOUT | WL_POSTMASTER_DEATH, - (nap.tv_sec * 1000L) + (nap.tv_usec / 1000L)); + (nap.tv_sec * 1000L) + (nap.tv_nsec / 1000000L)); ResetLatch(MyLatch); @@ -790,7 +790,7 @@ shutdown: * cause a long sleep, which will be interrupted when a worker exits. */ static void -launcher_determine_sleep(bool canlaunch, bool recursing, struct timeval * nap) +launcher_determine_sleep(bool canlaunch, bool recursing, struct timespec * nap) { /* * We sleep until the next scheduled vacuum. We trust that when the @@ -801,7 +801,7 @@ launcher_determine_sleep(bool canlaunch, bool recursing, struct timeval * nap) if (!canlaunch) { nap->tv_sec = autovacuum_naptime; - nap->tv_usec = 0; + nap->tv_nsec = 0; } else if (!dlist_is_empty(&DatabaseList)) { @@ -809,21 +809,21 @@ launcher_determine_sleep(bool canlaunch, bool recursing, struct timeval * nap) TimestampTz next_wakeup; avl_dbase *avdb; long secs; - int usecs; + int nsecs; avdb = dlist_tail_element(avl_dbase, adl_node, &DatabaseList); next_wakeup = avdb->adl_next_worker; - TimestampDifference(current_time, next_wakeup, &secs, &usecs); + TimestampDifference(current_time, next_wakeup, &secs, &nsecs); nap->tv_sec = secs; - nap->tv_usec = usecs; + nap->tv_nsec = nsecs; } else { /* list is empty, sleep for whole autovacuum_naptime seconds */ nap->tv_sec = autovacuum_naptime; - nap->tv_usec = 0; + nap->tv_nsec = 0; } /* @@ -836,7 +836,7 @@ launcher_determine_sleep(bool canlaunch, bool recursing, struct timeval * nap) * We only recurse once. rebuild_database_list should always return times * in the future, but it seems best not to trust too much on that. */ - if (nap->tv_sec == 0 && nap->tv_usec == 0 && !recursing) + if (nap->tv_sec == 0 && nap->tv_nsec == 0 && !recursing) { rebuild_database_list(InvalidOid); launcher_determine_sleep(canlaunch, true, nap); @@ -844,10 +844,10 @@ launcher_determine_sleep(bool canlaunch, bool recursing, struct timeval * nap) } /* The smallest time we'll allow the launcher to sleep. */ - if (nap->tv_sec <= 0 && nap->tv_usec <= MIN_AUTOVAC_SLEEPTIME * 1000) + if (nap->tv_sec <= 0 && nap->tv_nsec <= MIN_AUTOVAC_SLEEPTIME * 1000000) { nap->tv_sec = 0; - nap->tv_usec = MIN_AUTOVAC_SLEEPTIME * 1000; + nap->tv_nsec = MIN_AUTOVAC_SLEEPTIME * 1000; } /* diff --git a/src/backend/postmaster/checkpointer.c b/src/backend/postmaster/checkpointer.c index d702a48..eb0668c 100644 --- a/src/backend/postmaster/checkpointer.c +++ b/src/backend/postmaster/checkpointer.c @@ -725,7 +725,7 @@ static bool IsCheckpointOnSchedule(double progress) { XLogRecPtr recptr; - struct timeval now; + struct timespec now; double elapsed_xlogs, elapsed_time; @@ -778,9 +778,9 @@ IsCheckpointOnSchedule(double progress) /* * Check progress against time elapsed and checkpoint_timeout. */ - gettimeofday(&now, NULL); + clock_gettime(CLOCK_REALTIME, &now); elapsed_time = ((double) ((pg_time_t) now.tv_sec - ckpt_start_time) + - now.tv_usec / 1000000.0) / CheckPointTimeout; + now.tv_nsec / 1000000000.0) / CheckPointTimeout; if (progress < elapsed_time) { diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index eaf3f61..5277956 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -364,7 +364,7 @@ static volatile bool HaveCrashedWorker = false; * backend from the postmaster to that backend (via fork). */ static unsigned int random_seed = 0; -static struct timeval random_start_time; +static struct timespec random_start_time; #ifdef USE_BONJOUR static DNSServiceRef bonjour_sdref = NULL; @@ -1283,7 +1283,7 @@ PostmasterMain(int argc, char *argv[]) */ PgStartTime = GetCurrentTimestamp(); /* PostmasterRandom wants its own copy */ - gettimeofday(&random_start_time, NULL); + clock_gettime(CLOCK_REALTIME, &random_start_time); /* * We're ready to rock and roll... @@ -4208,7 +4208,7 @@ BackendRun(Port *port) * a new random sequence in the random() library function. */ random_seed = 0; - random_start_time.tv_usec = 0; + random_start_time.tv_nsec = 0; /* slightly hacky way to convert timestamptz into integers */ TimestampDifference(0, port->SessionStartTime, &secs, &usecs); srandom((unsigned int) (MyProcPid ^ (usecs << 12) ^ secs)); @@ -5111,19 +5111,19 @@ PostmasterRandom(void) { do { - struct timeval random_stop_time; + struct timespec random_stop_time; - gettimeofday(&random_stop_time, NULL); + clock_gettime(CLOCK_REALTIME, &random_stop_time); /* - * We are not sure how much precision is in tv_usec, so we swap + * We are not sure how much precision is in tv_nsec, so we swap * the high and low 16 bits of 'random_stop_time' and XOR them * with 'random_start_time'. On the off chance that the result is * 0, we loop until it isn't. */ - random_seed = random_start_time.tv_usec ^ - ((random_stop_time.tv_usec << 16) | - ((random_stop_time.tv_usec >> 16) & 0xffff)); + random_seed = random_start_time.tv_nsec ^ + ((random_stop_time.tv_nsec << 16) | + ((random_stop_time.tv_nsec >> 16) & 0xffff)); } while (random_seed == 0); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 98ccbbb..6d6accb 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -4374,13 +4374,13 @@ get_stack_depth_rlimit(void) static struct rusage Save_r; -static struct timeval Save_t; +static struct timespec Save_t; void ResetUsage(void) { getrusage(RUSAGE_SELF, &Save_r); - gettimeofday(&Save_t, NULL); + clock_gettime(CLOCK_REALTIME, &Save_t); } void @@ -4389,17 +4389,17 @@ ShowUsage(const char *title) StringInfoData str; struct timeval user, sys; - struct timeval elapse_t; + struct timespec elapse_t; struct rusage r; getrusage(RUSAGE_SELF, &r); - gettimeofday(&elapse_t, NULL); + clock_gettime(CLOCK_REALTIME, &elapse_t); memcpy((char *) &user, (char *) &r.ru_utime, sizeof(user)); memcpy((char *) &sys, (char *) &r.ru_stime, sizeof(sys)); - if (elapse_t.tv_usec < Save_t.tv_usec) + if (elapse_t.tv_nsec < Save_t.tv_nsec) { elapse_t.tv_sec--; - elapse_t.tv_usec += 1000000; + elapse_t.tv_nsec += 1000000000; } if (r.ru_utime.tv_usec < Save_r.ru_utime.tv_usec) { @@ -4425,7 +4425,7 @@ ShowUsage(const char *title) appendStringInfo(&str, "!\t%ld.%06ld elapsed %ld.%06ld user %ld.%06ld system sec\n", (long) (elapse_t.tv_sec - Save_t.tv_sec), - (long) (elapse_t.tv_usec - Save_t.tv_usec), + (long) (elapse_t.tv_nsec - Save_t.tv_nsec), (long) (r.ru_utime.tv_sec - Save_r.ru_utime.tv_sec), (long) (r.ru_utime.tv_usec - Save_r.ru_utime.tv_usec), (long) (r.ru_stime.tv_sec - Save_r.ru_stime.tv_sec), diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 224ee78..531aa69 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -147,7 +147,7 @@ static int recursion_depth = 0; /* to detect actual recursion */ * Saved timeval and buffers for formatted timestamps that might be used by * both log_line_prefix and csv logs. */ -static struct timeval saved_timeval; +static struct timespec saved_timeval; static bool saved_timeval_set = false; #define FORMATTED_TS_LEN 128 @@ -2232,7 +2232,7 @@ setup_formatted_log_time(void) if (!saved_timeval_set) { - gettimeofday(&saved_timeval, NULL); + clock_gettime(CLOCK_REALTIME_COARSE, &saved_timeval); saved_timeval_set = true; } @@ -2249,7 +2249,7 @@ setup_formatted_log_time(void) pg_localtime(&stamp_time, log_timezone)); /* 'paste' milliseconds into place... */ - sprintf(msbuf, ".%03d", (int) (saved_timeval.tv_usec / 1000)); + sprintf(msbuf, ".%03d", (int) (saved_timeval.tv_nsec / 1000000)); memcpy(formatted_log_time + 19, msbuf, 4); } @@ -2480,12 +2480,12 @@ log_line_prefix(StringInfo buf, ErrorData *edata) if (!saved_timeval_set) { - gettimeofday(&saved_timeval, NULL); + clock_gettime(CLOCK_REALTIME_COARSE, &saved_timeval); saved_timeval_set = true; } sprintf(strfbuf, "%ld.%03d", saved_timeval.tv_sec, - (int) (saved_timeval.tv_usec / 1000)); + (int) (saved_timeval.tv_nsec / 1000000)); if (padding != 0) appendStringInfo(buf, "%*s", padding, strfbuf); diff --git a/src/backend/utils/misc/pg_rusage.c b/src/backend/utils/misc/pg_rusage.c index 8781a38..5242dad 100644 --- a/src/backend/utils/misc/pg_rusage.c +++ b/src/backend/utils/misc/pg_rusage.c @@ -27,7 +27,7 @@ void pg_rusage_init(PGRUsage *ru0) { getrusage(RUSAGE_SELF, &ru0->ru); - gettimeofday(&ru0->tv, NULL); + clock_gettime(CLOCK_REALTIME, (struct timespec *)&ru0->tv); } /* diff --git a/src/bin/pg_basebackup/streamutil.c b/src/bin/pg_basebackup/streamutil.c index 595eaff..8481ec5 100644 --- a/src/bin/pg_basebackup/streamutil.c +++ b/src/bin/pg_basebackup/streamutil.c @@ -17,6 +17,7 @@ #include #include #include +#include #include /* for ntohl/htonl */ @@ -445,14 +446,14 @@ int64 feGetCurrentTimestamp(void) { int64 result; - struct timeval tp; + struct timespec tp; - gettimeofday(&tp, NULL); + clock_gettime(CLOCK_REALTIME_COARSE, &tp); result = (int64) tp.tv_sec - ((POSTGRES_EPOCH_JDATE - UNIX_EPOCH_JDATE) * SECS_PER_DAY); - result = (result * USECS_PER_SEC) + tp.tv_usec; + result = (result * NSECS_PER_SEC) + tp.tv_nsec; return result; } diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index ba9c276..9fc3a82 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -1756,7 +1756,7 @@ dumpTableData_copy(Archive *fout, void *dcontext) * Further discussion ensued, and the proposal was dropped. * * For those people who want this feature, it can be implemented using - * gettimeofday in each loop, calculating the time since last sleep, + * clock_gettime in each loop, calculating the time since last sleep, * multiplying that by the sleep ratio, then if the result is more * than a preset 'minimum sleep time' (say 100ms), call the 'select' * function to sleep for a subsecond period ie. @@ -1764,7 +1764,7 @@ dumpTableData_copy(Archive *fout, void *dcontext) * select(0, NULL, NULL, NULL, &tvi); * * This will return after the interval specified in the structure tvi. - * Finally, call gettimeofday again to save the 'last sleep time'. + * Finally, call clock_gettime again to save the 'last sleep time'. * ---------- */ } diff --git a/src/bin/pg_resetxlog/pg_resetxlog.c b/src/bin/pg_resetxlog/pg_resetxlog.c index 525b82ba..cc9b03e 100644 --- a/src/bin/pg_resetxlog/pg_resetxlog.c +++ b/src/bin/pg_resetxlog/pg_resetxlog.c @@ -535,7 +535,7 @@ static void GuessControlValues(void) { uint64 sysidentifier; - struct timeval tv; + struct timespec tv; /* * Set up a completely default set of pg_control values. @@ -550,9 +550,9 @@ GuessControlValues(void) * Create a new unique installation identifier, since we can no longer use * any old XLOG records. See notes in xlog.c about the algorithm. */ - gettimeofday(&tv, NULL); + clock_gettime(CLOCK_REALTIME_COARSE, &tv); sysidentifier = ((uint64) tv.tv_sec) << 32; - sysidentifier |= ((uint64) tv.tv_usec) << 12; + sysidentifier |= ((uint64) tv.tv_nsec) << 12; sysidentifier |= getpid() & 0xFFF; ControlFile.system_identifier = sysidentifier; diff --git a/src/bin/pg_test_fsync/pg_test_fsync.c b/src/bin/pg_test_fsync/pg_test_fsync.c index c842762..ca8206e 100644 --- a/src/bin/pg_test_fsync/pg_test_fsync.c +++ b/src/bin/pg_test_fsync/pg_test_fsync.c @@ -26,7 +26,7 @@ #define LABEL_FORMAT " %-30s" #define NA_FORMAT "%20s" #define OPS_FORMAT "%13.3f ops/sec %6.0f usecs/op" -#define USECS_SEC 1000000 +#define NSECS_SEC 1000000000 /* These are macros to avoid timing the function call overhead. */ #ifndef WIN32 @@ -34,7 +34,7 @@ do { \ alarm_triggered = false; \ alarm(secs_per_test); \ - gettimeofday(&start_t, NULL); \ + clock_gettime(CLOCK_REALTIME, &start_t); \ } while (0) #else /* WIN32 doesn't support alarm, so we create a thread and sleep there */ @@ -47,13 +47,13 @@ do { \ fprintf(stderr, "Cannot create thread for alarm\n"); \ exit(1); \ } \ - gettimeofday(&start_t, NULL); \ -} while (0) + clock_gettime(CLOCK_REALTIME, &start_t); \ + } while (0) #endif #define STOP_TIMER \ do { \ - gettimeofday(&stop_t, NULL); \ + clock_gettime(CLOCK_REALTIME, &stop_t); \ print_elapse(start_t, stop_t, ops); \ } while (0) @@ -65,7 +65,7 @@ static int needs_unlink = 0; static char full_buf[XLOG_SEG_SIZE], *buf, *filename = FSYNC_FILENAME; -static struct timeval start_t, +static struct timespec start_t, stop_t; static bool alarm_triggered = false; @@ -89,7 +89,7 @@ static void signal_cleanup(int sig); #ifdef HAVE_FSYNC_WRITETHROUGH static int pg_fsync_writethrough(int fd); #endif -static void print_elapse(struct timeval start_t, struct timeval stop_t, int ops); +static void print_elapse(struct timespec start_t, struct timespec stop_t, int ops); static void die(const char *str); @@ -568,12 +568,12 @@ pg_fsync_writethrough(int fd) * print out the writes per second for tests */ static void -print_elapse(struct timeval start_t, struct timeval stop_t, int ops) +print_elapse(struct timespec start_t, struct timespec stop_t, int ops) { double total_time = (stop_t.tv_sec - start_t.tv_sec) + - (stop_t.tv_usec - start_t.tv_usec) * 0.000001; + (stop_t.tv_nsec - start_t.tv_nsec) * 0.000000001; double per_second = ops / total_time; - double avg_op_time_us = (total_time / ops) * USECS_SEC; + double avg_op_time_us = (total_time / ops) * NSECS_SEC; printf(OPS_FORMAT "\n", per_second, avg_op_time_us); } diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c index 56c37d5..d10fe51 100644 --- a/src/bin/pgbench/pgbench.c +++ b/src/bin/pgbench/pgbench.c @@ -1772,7 +1772,7 @@ doCustom(TState *thread, CState *st, StatsData *agg) instr_time now; /* - * gettimeofday() isn't free, so we get the current timestamp lazily the + * clock_gettime() isn't free, so we get the current timestamp lazily the * first time it's needed, and reuse the same value throughout this * function after that. This also ensures that e.g. the calculated latency * reported in the log file and in the totals are the same. Zero means @@ -2247,11 +2247,11 @@ doLog(TState *thread, CState *st, instr_time *now, if (skipped) fprintf(logfile, "%d " INT64_FORMAT " skipped %d %ld %ld", st->id, st->cnt, st->use_file, - (long) now->tv_sec, (long) now->tv_usec); + (long) now->tv_sec, (long) now->tv_nsec); else fprintf(logfile, "%d " INT64_FORMAT " %.0f %d %ld %ld", st->id, st->cnt, latency, st->use_file, - (long) now->tv_sec, (long) now->tv_usec); + (long) now->tv_sec, (long) now->tv_nsec); #else /* On Windows, instr_time doesn't provide a timestamp anyway */ diff --git a/src/include/c.h b/src/include/c.h index 4ab3f80..020fa30 100644 --- a/src/include/c.h +++ b/src/include/c.h @@ -138,6 +138,16 @@ */ #define gettext_noop(x) (x) +#if defined(WIN32) || defined(__CYGWIN__) +typedef struct timespec { + long tv_sec; + long tv_nsec; +} timespec; + +#define CLOCK_REALTIME 1 +#define CLOCK_REALTIME_COARSE 2 +#endif + /* ---------------------------------------------------------------- * Section 1: hacks to cope with non-ANSI C compilers diff --git a/src/include/datatype/timestamp.h b/src/include/datatype/timestamp.h index 68a41eb..31d39d8 100644 --- a/src/include/datatype/timestamp.h +++ b/src/include/datatype/timestamp.h @@ -105,6 +105,9 @@ typedef struct #define USECS_PER_MINUTE INT64CONST(60000000) #define USECS_PER_SEC INT64CONST(1000000) +#define NSECS_PER_SEC INT64CONST(1000000000) +#define NSECS_PER_USEC INT64CONST(1000) + /* * We allow numeric timezone offsets up to 15:59:59 either way from Greenwich. * Currently, the record holders for wackiest offsets in actual use are zones diff --git a/src/include/pg_config.h.in b/src/include/pg_config.h.in index b621ff2..e2efae7 100644 --- a/src/include/pg_config.h.in +++ b/src/include/pg_config.h.in @@ -231,6 +231,9 @@ /* Define to 1 if you have the `gettimeofday' function. */ #undef HAVE_GETTIMEOFDAY +/* Define to 1 if you have the `clock_gettime' function. */ +#undef HAVE_CLOCK_GETTIME + /* Define to 1 if you have the header file. */ #undef HAVE_GSSAPI_GSSAPI_H diff --git a/src/include/port.h b/src/include/port.h index b81fa4a..a8e80dc 100644 --- a/src/include/port.h +++ b/src/include/port.h @@ -319,6 +319,11 @@ extern FILE *pgwin32_popen(const char *command, const char *type); /* Last parameter not used */ extern int gettimeofday(struct timeval * tp, struct timezone * tzp); #endif +/* New versions of MingW have gettimeofday, old mingw and msvc don't */ +#ifndef HAVE_CLOCK_GETTIME +/* First parameter is not used */ +extern int clock_gettime(int clock_id, struct timespec * tp); +#endif #else /* !WIN32 */ /* diff --git a/src/include/portability/instr_time.h b/src/include/portability/instr_time.h index 16caf6e..ebcc976 100644 --- a/src/include/portability/instr_time.h +++ b/src/include/portability/instr_time.h @@ -4,7 +4,7 @@ * portable high-precision interval timing * * This file provides an abstraction layer to hide portability issues in - * interval timing. On Unix we use gettimeofday(), but on Windows that + * interval timing. On Unix we use clock_gettime(), but on Windows that * gives a low-precision result so we must use QueryPerformanceCounter() * instead. These macros also give some breathing room to use other * high-precision-timing APIs on yet other platforms. @@ -54,24 +54,24 @@ #ifndef WIN32 -#include +#include -typedef struct timeval instr_time; +typedef struct timespec instr_time; -#define INSTR_TIME_IS_ZERO(t) ((t).tv_usec == 0 && (t).tv_sec == 0) +#define INSTR_TIME_IS_ZERO(t) ((t).tv_nsec == 0 && (t).tv_sec == 0) -#define INSTR_TIME_SET_ZERO(t) ((t).tv_sec = 0, (t).tv_usec = 0) +#define INSTR_TIME_SET_ZERO(t) ((t).tv_sec = 0, (t).tv_nsec = 0) -#define INSTR_TIME_SET_CURRENT(t) gettimeofday(&(t), NULL) +#define INSTR_TIME_SET_CURRENT(t) clock_gettime(CLOCK_REALTIME, &(t)) #define INSTR_TIME_ADD(x,y) \ do { \ (x).tv_sec += (y).tv_sec; \ - (x).tv_usec += (y).tv_usec; \ + (x).tv_nsec += (y).tv_nsec; \ /* Normalize */ \ - while ((x).tv_usec >= 1000000) \ + while ((x).tv_nsec >= 1000000000) \ { \ - (x).tv_usec -= 1000000; \ + (x).tv_nsec -= 1000000000; \ (x).tv_sec++; \ } \ } while (0) @@ -79,11 +79,11 @@ typedef struct timeval instr_time; #define INSTR_TIME_SUBTRACT(x,y) \ do { \ (x).tv_sec -= (y).tv_sec; \ - (x).tv_usec -= (y).tv_usec; \ + (x).tv_nsec -= (y).tv_nsec; \ /* Normalize */ \ - while ((x).tv_usec < 0) \ + while ((x).tv_nsec < 0) \ { \ - (x).tv_usec += 1000000; \ + (x).tv_nsec += 1000000000; \ (x).tv_sec--; \ } \ } while (0) @@ -91,28 +91,28 @@ typedef struct timeval instr_time; #define INSTR_TIME_ACCUM_DIFF(x,y,z) \ do { \ (x).tv_sec += (y).tv_sec - (z).tv_sec; \ - (x).tv_usec += (y).tv_usec - (z).tv_usec; \ + (x).tv_nsec += (y).tv_nsec - (z).tv_nsec; \ /* Normalize after each add to avoid overflow/underflow of tv_usec */ \ - while ((x).tv_usec < 0) \ + while ((x).tv_nsec < 0) \ { \ - (x).tv_usec += 1000000; \ + (x).tv_nsec += 1000000000; \ (x).tv_sec--; \ } \ - while ((x).tv_usec >= 1000000) \ + while ((x).tv_nsec >= 1000000000) \ { \ - (x).tv_usec -= 1000000; \ + (x).tv_nsec -= 1000000; \ (x).tv_sec++; \ } \ } while (0) #define INSTR_TIME_GET_DOUBLE(t) \ - (((double) (t).tv_sec) + ((double) (t).tv_usec) / 1000000.0) + (((double) (t).tv_sec) + ((double) (t).tv_nsec) / 1000000000.0) #define INSTR_TIME_GET_MILLISEC(t) \ - (((double) (t).tv_sec * 1000.0) + ((double) (t).tv_usec) / 1000.0) + (((double) (t).tv_sec * 1000.0) + ((double) (t).tv_nsec) / 1000000.0) #define INSTR_TIME_GET_MICROSEC(t) \ - (((uint64) (t).tv_sec * (uint64) 1000000) + (uint64) (t).tv_usec) + (((uint64) (t).tv_sec * (uint64) 1000000) + ((double) (t).tv_nsec) / 1000.0) #else /* WIN32 */ typedef LARGE_INTEGER instr_time; diff --git a/src/include/utils/pg_rusage.h b/src/include/utils/pg_rusage.h index 7c264eb..9ca9436 100644 --- a/src/include/utils/pg_rusage.h +++ b/src/include/utils/pg_rusage.h @@ -15,6 +15,7 @@ #define PG_RUSAGE_H #include +#include #ifdef HAVE_SYS_RESOURCE_H #include diff --git a/src/port/clock_gettime.c b/src/port/clock_gettime.c new file mode 100644 index 0000000..05641ad --- /dev/null +++ b/src/port/clock_gettime.c @@ -0,0 +1,117 @@ +/* + * clock_gettime.c + * Win32 clock_gettime() replacement + * + * src/port/clock_gettime.c + * + * Copyright (c) 2003 SRA, Inc. + * Copyright (c) 2003 SKC, Inc. + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose, without fee, and without a + * written agreement is hereby granted, provided that the above + * copyright notice and this paragraph and the following two + * paragraphs appear in all copies. + * + * IN NO EVENT SHALL THE AUTHOR BE LIABLE TO ANY PARTY FOR DIRECT, + * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING + * LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS + * DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * THE AUTHOR SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS + * IS" BASIS, AND THE AUTHOR HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, + * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + */ + +#include "c.h" + +#include + +/* FILETIME of Jan 1 1970 00:00:00, the PostgreSQL epoch */ +static const unsigned __int64 epoch = UINT64CONST(116444736000000000); + +/* + * FILETIME represents the number of 100-nanosecond intervals since + * January 1, 1601 (UTC). + */ +#define FILETIME_UNITS_PER_SEC 10000000L +#define FILETIME_UNITS_PER_USEC 10 + +/* + * Both GetSystemTimeAsFileTime and GetSystemTimePreciseAsFileTime share a + * signature, so we can just store a pointer to whichever we find. This + * is the pointer's type. + */ +typedef VOID(WINAPI * PgGetSystemTimeFn) (LPFILETIME); + +/* One-time initializer function, must match that signature. */ +static void WINAPI init_clock_gettime(LPFILETIME lpSystemTimeAsFileTime); + +/* Storage for the function we pick at runtime */ +static PgGetSystemTimeFn pg_get_system_time = &init_clock_gettime; + +/* + * One time initializer. Determine whether GetSystemTimePreciseAsFileTime + * is available and if so, plan to use it; if not, fall back to + * GetSystemTimeAsFileTime. + */ +static void WINAPI +init_clock_gettime(LPFILETIME lpSystemTimeAsFileTime) +{ + /* + * Because it's guaranteed that kernel32.dll will be linked into our + * address space already, we don't need to LoadLibrary it and worry about + * closing it afterwards, so we're not using Pg's dlopen/dlsym() wrapper. + * + * We'll just look up the address of GetSystemTimePreciseAsFileTime if + * present. + * + * While we could look up the Windows version and skip this on Windows + * versions below Windows 8 / Windows Server 2012 there isn't much point, + * and determining the windows version is its self somewhat Windows + * version and development SDK specific... + */ + pg_get_system_time = (PgGetSystemTimeFn) GetProcAddress( + GetModuleHandle(TEXT("kernel32.dll")), + "GetSystemTimePreciseAsFileTime"); + if (pg_get_system_time == NULL) + { + /* + * The expected error from GetLastError() is ERROR_PROC_NOT_FOUND, if + * the function isn't present. No other error should occur. + * + * We can't report an error here because this might be running in + * frontend code; and even if we're in the backend, it's too early to + * elog(...) if we get some unexpected error. Also, it's not a + * serious problem, so just silently fall back to + * GetSystemTimeAsFileTime irrespective of why the failure occurred. + */ + pg_get_system_time = &GetSystemTimeAsFileTime; + } + + (*pg_get_system_time) (lpSystemTimeAsFileTime); +} + +/* + * Note: this function is not for Win32 high precision timing purposes. See + * elapsed_time(). + */ +int +clock_gettime(int clock_id, struct timespec * tp) +{ + FILETIME file_time; + ULARGE_INTEGER ularge; + + (*pg_get_system_time) (&file_time); + ularge.LowPart = file_time.dwLowDateTime; + ularge.HighPart = file_time.dwHighDateTime; + + tp->tv_sec = (long) ((ularge.QuadPart - epoch) / FILETIME_UNITS_PER_SEC); + tp->tv_nsec = (long) ((((ularge.QuadPart - epoch) % FILETIME_UNITS_PER_SEC) + / FILETIME_UNITS_PER_USEC) * 1000); + + return 0; +} diff --git a/src/test/isolation/isolationtester.c b/src/test/isolation/isolationtester.c index db2b559..d31aef5 100644 --- a/src/test/isolation/isolationtester.c +++ b/src/test/isolation/isolationtester.c @@ -11,6 +11,7 @@ #include #endif #include +#include #ifdef HAVE_SYS_SELECT_H #include #endif @@ -698,7 +699,7 @@ try_complete_step(Step *step, int flags) { PGconn *conn = conns[1 + step->session]; fd_set read_set; - struct timeval start_time; + struct timespec start_time; struct timeval timeout; int sock = PQsocket(conn); int ret; @@ -711,7 +712,7 @@ try_complete_step(Step *step, int flags) exit_nicely(); } - gettimeofday(&start_time, NULL); + clock_gettime(CLOCK_REALTIME, &start_time); FD_ZERO(&read_set); while (PQisBusy(conn)) @@ -730,7 +731,7 @@ try_complete_step(Step *step, int flags) } else if (ret == 0) /* select() timeout: check for lock wait */ { - struct timeval current_time; + struct timespec current_time; int64 td; /* If it's OK for the step to block, check whether it has. */ @@ -762,10 +763,10 @@ try_complete_step(Step *step, int flags) } /* Figure out how long we've been waiting for this step. */ - gettimeofday(¤t_time, NULL); + clock_gettime(CLOCK_REALTIME, ¤t_time); td = (int64) current_time.tv_sec - (int64) start_time.tv_sec; - td *= USECS_PER_SEC; - td += (int64) current_time.tv_usec - (int64) start_time.tv_usec; + td *= NSECS_PER_SEC; + td += (int64) current_time.tv_nsec - (int64) start_time.tv_nsec; /* * After 60 seconds, try to cancel the query. @@ -776,7 +777,7 @@ try_complete_step(Step *step, int flags) * presumably lead to this permutation failing, but remaining * permutations and tests should still be OK. */ - if (td > 60 * USECS_PER_SEC && !canceled) + if (td > 60 * NSECS_PER_SEC && !canceled) { PGcancel *cancel = PQgetCancel(conn); @@ -799,7 +800,7 @@ try_complete_step(Step *step, int flags) * later tests to fail. That stinks, but it's better than waiting * forever for the server to respond to the cancel. */ - if (td > 75 * USECS_PER_SEC) + if (td > 75 * NSECS_PER_SEC) { fprintf(stderr, "step %s timed out after 75 seconds\n", step->name); diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 93dfd24..1b16684 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -88,8 +88,8 @@ sub mkvcbuild $solution = CreateSolution($vsVersion, $config); our @pgportfiles = qw( - chklocale.c crypt.c fls.c fseeko.c getrusage.c inet_aton.c random.c - srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c + chklocale.c clock_gettime.c crypt.c fls.c fseeko.c getrusage.c inet_aton.c + random.c srandom.c getaddrinfo.c gettimeofday.c inet_net_ntop.c kill.c open.c erand48.c snprintf.c strlcat.c strlcpy.c dirmod.c noblock.c path.c pgcheckdir.c pgmkdirp.c pgsleep.c pgstrcasecmp.c pqsignal.c mkdtemp.c qsort.c qsort_arg.c quotes.c system.c