[q-lang-cvs] q/modules/clib system.c,1.5,1.6 system.q,1.5,1.6
Brought to you by:
agraef
From: Albert G. <ag...@us...> - 2008-02-23 08:37:34
|
Update of /cvsroot/q-lang/q/modules/clib In directory sc8-pr-cvs16.sourceforge.net:/tmp/cvs-serv29126/modules/clib Modified Files: system.c system.q Log Message: add hires timer functions Index: system.q =================================================================== RCS file: /cvsroot/q-lang/q/modules/clib/system.q,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** system.q 23 Jan 2008 05:24:32 -0000 1.5 --- system.q 23 Feb 2008 08:37:30 -0000 1.6 *************** *** 34,39 **** using bitwise logical operations as usual. Flag values which are unavailable on the host system will be set to zero, other undefined values ! to -1. Thus undefined values will generally have no effect or cause the ! corresponding operations to fail. */ public var const --- 34,39 ---- using bitwise logical operations as usual. Flag values which are unavailable on the host system will be set to zero, other undefined values ! to -1 (or () in some cases). Thus undefined values will generally have no ! effect or cause the corresponding operations to fail. */ public var const *************** *** 145,148 **** --- 145,153 ---- IPPROTO_IP, IPPROTO_ICMP, IPPROTO_TCP, IPPROTO_UDP, + /* highres timers *********************************************************/ + + CLOCK_REALTIME, CLOCK_MONOTONIC, + CLOCK_PROCESS_CPUTIME, CLOCK_THREAD_CPUTIME, + /* locale-related constants ***********************************************/ *************** *** 241,244 **** --- 246,252 ---- IPPROTO_IP, IPPROTO_ICMP, IPPROTO_TCP, IPPROTO_UDP, + CLOCK_REALTIME, CLOCK_MONOTONIC, + CLOCK_PROCESS_CPUTIME, CLOCK_THREAD_CPUTIME, + LC_ALL, LC_COLLATE, LC_CTYPE, LC_MESSAGES, LC_MONETARY, LC_NUMERIC, LC_TIME, *************** *** 704,710 **** /* Time functions. Return information about the active timezone and the current time, and convert time values to various formats. Also available ! are functions to measure cpu time. These functions are in close ! correspondence with the date and time functions of the C library, see the ! manual for details. */ /* Simple time (T) is represented as seconds since the "epoch", broken-down --- 712,718 ---- /* Time functions. Return information about the active timezone and the current time, and convert time values to various formats. Also available ! are functions to measure cpu time and a high-resolution timer. These ! functions are in close correspondence with the date and time functions of ! the C library, see the manual for details. */ /* Simple time (T) is represented as seconds since the "epoch", broken-down *************** *** 739,742 **** --- 747,799 ---- public extern clock, times; + /* High-resolution timers (U). This requires the POSIX 1003.1-2001 timer + extension, otherwise these functions will fail. Note that these operations + differ from the builtin time and sleep functions in that they use integer + (unsigned 64 bit) time values specified in nanoseconds. The nanotime + function returns the current time in nanosecs, the nanores function the + resolution of the given timer. The nanosleep function sleeps for the + specified amount of nanoseconds, while the nanosleep_until function sleeps + until the given (absolute) time arrives. (Just like the sleep function, + these functions may exit early if a signal is delivered to the process; see + the manual for details.) In case of any error condition, these functions + will set errno accordingly. + + For each of the functions you have to specify an integer-valued timer + id. In the current implementation, the following timers are supported: + + - CLOCK_REALTIME: The system clock, measured in nanosecs since the epoch. + This will be the same time as returned by the builtin time function (up + to rounding issues with the latter). + + - CLOCK_MONOTONIC: Monotonic (non-decreasing) time since some unspecified + starting point. This clock cannot be reset by the user and is thus to be + preferred in realtime applications. + + - CLOCK_PROCESS_CPUTIME, CLOCK_THREAD_CPUTIME: Highres per-process and + per-thread CPU timers. (Normally these are for timing purposes only and + might be unreliable on SMP systems, see clock_gettime(3) for details.) + + Only CLOCK_REALTIME is guaranteed to be available (on systems which + implement the highres timers at all, that is). If a given clock is + unavailable on the host system, the corresponding id will be () (if + CLOCK_REALTIME is (), then the highres timers are not supported at all). + + Moreover, if CPU timers are available, then the process_cpu_clockid and + thread_cpu_clockid functions can be used to return the clock id for the + given process id (0 denotes the current process) and the given thread, + respectively. + + CAVEAT: While these timers nominally support nanoseconds resolution, the + actual resolutions depend on your system setup and will typically be much + coarser (for the system and monotonic clocks, they are usually in the + milliseconds range on current PCs). Also, you must consider system + latencies which might cause calls to nanosleep and nanosleep_until to wake + up late on occasions (use realtime scheduling priorities to mitigate these + effects). */ + + public extern nanotime ID, nanores ID; + public extern nanosleep ID T, nanosleep_until ID T; + public extern process_cpu_clockid PID, thread_cpu_clockid THREAD; + /****************************************************************************/ Index: system.c =================================================================== RCS file: /cvsroot/q-lang/q/modules/clib/system.c,v retrieving revision 1.5 retrieving revision 1.6 diff -C2 -d -r1.5 -r1.6 *** system.c 23 Jan 2008 05:24:32 -0000 1.5 --- system.c 23 Feb 2008 08:37:30 -0000 1.6 *************** *** 316,319 **** --- 316,338 ---- #endif + /* make sure that this matches up with the declaration in clib.c */ + + typedef unsigned char bool; + typedef struct { + bool active, canceled, used; /* status */ + expr arg; /* thread argument */ + expr result; /* thread result, if any */ + expr thread; /* thread object */ + #ifdef USE_THREADS + pthread_t id; /* thread id */ + pthread_mutex_t exit_mutex; /* exit mutex and condition */ + pthread_cond_t exit_cond; + #ifdef WIN32 + HANDLE handle; /* thread handle */ + int pol; /* scheduling policy */ + #endif + #endif + } THREAD; + MODULE(system) *************** *** 1478,1482 **** if (argc != 0) return __FAIL; return mktuplel ! (242, mkint(P_WAIT), mkint(P_NOWAIT), mkint(P_OVERLAY), mkint(P_DETACH), --- 1497,1501 ---- if (argc != 0) return __FAIL; return mktuplel ! (246, mkint(P_WAIT), mkint(P_NOWAIT), mkint(P_OVERLAY), mkint(P_DETACH), *************** *** 1663,1666 **** --- 1682,1709 ---- mkint(IPPROTO_UDP), + #ifdef _POSIX_TIMERS + mkint(CLOCK_REALTIME), + #ifdef _POSIX_MONOTONIC_CLOCK + mkint(CLOCK_MONOTONIC), + #else + mkvoid, + #endif + #ifdef _POSIX_CPUTIME + mkint(CLOCK_PROCESS_CPUTIME_ID), + #else + mkvoid, + #endif + #ifdef _POSIX_THREAD_CPUTIME + mkint(CLOCK_THREAD_CPUTIME_ID), + #else + mkvoid, + #endif + #else + mkvoid, + mkvoid, + mkvoid, + mkvoid, + #endif + #ifdef HAVE_LOCALE_H mkint(LC_ALL), *************** *** 5544,5547 **** --- 5587,5740 ---- } + FUNCTION(system,nanotime,argc,argv) + { + #ifdef HAVE_CLOCK_GETTIME + long id; + if (argc == 1 && isint(argv[0], &id)) { + struct timespec tv; + int res = clock_gettime(id, &tv); + if (res) + return __FAIL; + else { + mpz_t z; + /* two limbs should always be enough */ + if (!mpz_new(z, 2)) return __ERROR; + mpz_set_ui(z, tv.tv_sec); + mpz_mul_ui(z, z, 1000000000UL); + mpz_add_ui(z, z, tv.tv_nsec); + if (!mpz_actsize(z)) return __ERROR; + return mkmpz(z); + } + } else + #endif + return __FAIL; + } + + FUNCTION(system,nanores,argc,argv) + { + #ifdef HAVE_CLOCK_GETRES + long id; + if (argc == 1 && isint(argv[0], &id)) { + struct timespec tv; + int res = clock_getres(id, &tv); + if (res) + return __FAIL; + else { + mpz_t z; + /* two limbs should always be enough */ + if (!mpz_new(z, 2)) return __ERROR; + mpz_set_ui(z, tv.tv_sec); + mpz_mul_ui(z, z, 1000000000UL); + mpz_add_ui(z, z, tv.tv_nsec); + if (!mpz_actsize(z)) return __ERROR; + return mkmpz(z); + } + } else + #endif + return __FAIL; + } + + FUNCTION(system,nanosleep,argc,argv) + { + #ifdef HAVE_CLOCK_NANOSLEEP + long id; + mpz_t z; + if (argc == 2 && isint(argv[0], &id) && ismpz(argv[1], z)) { + int res; + struct timespec tv, rv; + mpz_t s, n; + int l = mpz_size(z); + if (l <= 0) l = 1; + if (!mpz_new(s, l)) return __ERROR; + if (!mpz_new(n, 1)) return __ERROR; + mpz_fdiv_qr_ui(s, n, z, 1000000000UL); + tv.tv_sec = s->_mp_d[0]; + tv.tv_nsec = n->_mp_d[0]; + mpz_clear(s); mpz_clear(n); + res = clock_nanosleep(id, 0, &tv, &rv); + if (res == EINTR) { + /* interrupt, return remaining time */ + mpz_t z; + if (!mpz_new(z, 2)) return __ERROR; + mpz_set_ui(z, rv.tv_sec); + mpz_mul_ui(z, z, 1000000000UL); + mpz_add_ui(z, z, rv.tv_nsec); + if (!mpz_actsize(z)) return __ERROR; + errno = res; + return mkmpz(z); + } else if (res) { + /* other error, set errno appropriately */ + errno = res; + return __FAIL; + } else + /* sleep timed out, return 0 to indicate success */ + return mkint(0); + } else + #endif + return __FAIL; + } + + FUNCTION(system,nanosleep_until,argc,argv) + { + #ifdef HAVE_CLOCK_NANOSLEEP + long id; + mpz_t z; + if (argc == 2 && isint(argv[0], &id) && ismpz(argv[1], z)) { + int res; + struct timespec tv; + mpz_t s, n; + int l = mpz_size(z); + if (l <= 0) l = 1; + if (!mpz_new(s, l)) return __ERROR; + if (!mpz_new(n, 1)) return __ERROR; + mpz_fdiv_qr_ui(s, n, z, 1000000000UL); + tv.tv_sec = s->_mp_d[0]; + tv.tv_nsec = n->_mp_d[0]; + mpz_clear(s); mpz_clear(n); + res = clock_nanosleep(id, TIMER_ABSTIME, &tv, NULL); + if (res) { + errno = res; + return __FAIL; + } else + return mkvoid; + } else + #endif + return __FAIL; + } + + FUNCTION(system,process_cpu_clockid,argc,argv) + { + #ifdef _POSIX_CPUTIME + long pid; + if (argc == 1 && isint(argv[0], &pid)) { + clockid_t id; + int res = clock_getcpuclockid(pid, &id); + if (res) { + errno = res; + return __FAIL; + } else + return mkint(id); + } else + #endif + return __FAIL; + } + + FUNCTION(system,thread_cpu_clockid,argc,argv) + { + #ifdef _POSIX_THREAD_CPUTIME + THREAD *thr; + if (argc == 1 && isobj(argv[0], type(Thread), (void**)&thr)) { + clockid_t id; + int res = pthread_getcpuclockid(thr->id, &id); + if (res) { + errno = res; + return __FAIL; + } else + return mkint(id); + } else + #endif + return __FAIL; + } + /* i18n functions: ********************************************************/ |