diff options
| author | Tyge Løvset <[email protected]> | 2023-06-05 19:02:03 +0200 |
|---|---|---|
| committer | Tyge Løvset <[email protected]> | 2023-06-05 19:13:22 +0200 |
| commit | 4b8f8d2a97ca1411ad6dccdeac6195574edac852 (patch) | |
| tree | c744f00c4288d3e8988a07b417c754ca5db17f4a | |
| parent | 2d3250d2d35dda415840d8403b7b8957ca40914a (diff) | |
| download | STC-modified-4b8f8d2a97ca1411ad6dccdeac6195574edac852.tar.gz STC-modified-4b8f8d2a97ca1411ad6dccdeac6195574edac852.zip | |
Updated timers and time functions to microseconds (from milli).
| -rw-r--r-- | docs/ccommon_api.md | 12 | ||||
| -rw-r--r-- | include/stc/algo/coroutine.h | 79 | ||||
| -rw-r--r-- | misc/examples/dining_philosophers.c | 12 |
3 files changed, 64 insertions, 39 deletions
diff --git a/docs/ccommon_api.md b/docs/ccommon_api.md index 4d18120a..6276494b 100644 --- a/docs/ccommon_api.md +++ b/docs/ccommon_api.md @@ -379,25 +379,27 @@ To resume the coroutine from where it was suspended with *cco_yield()*, simply c | | `cco_yield(ret)` | Yield/suspend execution and return ret | | | `cco_await(promise)` | Await/suspend until promise is true | | | `cco_await(promise, ret)` | Await/suspend with ret value | -| | `cco_sleep(long msec)` | Sleep for milliseconds | | | Semaphores: | | | | `cco_sem` | Semaphore type | | | `cco_sem_await(sem)` | Await for the semaphore count > 0 | | | `cco_sem_await(sem, ret)` | Await with ret on the semaphore | -| cco_sem | `cco_sem_init(long value)` | Set semaphore value | +| `cco_sem` | `cco_sem_init(long value)` | Set semaphore value | | | `cco_sem_release(sem)` | Signal the semaphore | | | Timers: | | | | `cco_timer` | Timer type | | | `cco_timer_await(tm)` | Await for timer to expire | | | `cco_timer_await(tm, ret)` | Await with ret for timer to expire | -| | `cco_timer_start(tm, long msecs)` | Start timer msecs milliseconds | +| | `cco_timer_start(tm, long usec)` | Start timer for usec microseconds | | | `cco_timer_restart(tm)` | Restart timer with same duration | | `bool` | `cco_timer_expired(tm)` | Return true if timer is expired | -| `long` | `cco_timer_remaining(tm)` | Return milliseconds remaining | +|`long long`| `cco_timer_remaining(tm)` | Return microseconds remaining | | | From caller side: | | -| `void` | `cco_stop(co)` | Next call of coroutine returns `cco_end()` | +| `void` | `cco_stop(co)` | Next call of coroutine finalizes | | `void` | `cco_reset(co)` | Reset state to initial (for reuse) | | `void` | `cco_run(co, corocall) { }` | Run blocking until coro is done | +| | Time functions: | | +|`long long`| `cco_utime(void)` | Return microseconds since Epoch | +| | `cco_usleep(long long usec)` | Sleep for microseconds | --- ## RAII scope macros diff --git a/include/stc/algo/coroutine.h b/include/stc/algo/coroutine.h index 05307b08..d0c9ad86 100644 --- a/include/stc/algo/coroutine.h +++ b/include/stc/algo/coroutine.h @@ -56,7 +56,6 @@ int main(void) { return 0; } */ -#include <time.h> #include <stc/ccommon.h> enum { @@ -130,55 +129,77 @@ typedef struct { * Timer */ -typedef struct { - clock_t start; - clock_t interval; -} cco_timer; - -#define cco_timer_await(...) c_MACRO_OVERLOAD(cco_timer_await, __VA_ARGS__) -#define cco_timer_await_2(tm, msec) cco_timer_await_3(tm, msec, ) -#define cco_timer_await_3(tm, msec, ret) \ - do { \ - cco_timer_start(tm, msec); \ - cco_await_2(cco_timer_expired(tm), ret); \ - } while (0) - #ifdef _WIN32 #ifdef __cplusplus - extern "C" + #define _c_LINKC extern "C" __declspec(dllimport) + #else + #define _c_LINKC __declspec(dllimport) #endif - __declspec(dllimport) void __stdcall Sleep(unsigned long); - static inline void cco_sleep(long msec) { - Sleep((unsigned long)msec); + struct _FILETIME; struct _SECURITY_ATTRIBUTES; union _LARGE_INTEGER; + _c_LINKC void GetSystemTimePreciseAsFileTime(struct _FILETIME*); + _c_LINKC void* CreateWaitableTimerW(struct _SECURITY_ATTRIBUTES*, int, const wchar_t*); + _c_LINKC int SetWaitableTimer(void*, const union _LARGE_INTEGER*, long, void(*)(void*, unsigned long, unsigned long), void*, int); + _c_LINKC unsigned long WaitForSingleObject(void*, unsigned long); + _c_LINKC int CloseHandle(void*); + + static inline long long cco_utime(void) { + static const long long epoch_offset = 11644473600000000LL; /* microseconds betweeen Jan 1,1601 - Jan 1,1970 */ + unsigned long long quad; /* 64-bit value, 100-nanosecond intervals since January 1, 1601 00:00 UTC */ + GetSystemTimePreciseAsFileTime((struct _FILETIME*)&quad); + return (long long)quad/10 - epoch_offset; /* microseconds since epoch */ } + + static inline void cco_usleep(long long usec) { + unsigned long long ft = -10*usec; + void* timer = CreateWaitableTimerW(NULL, true, NULL); + SetWaitableTimer(timer, (const union _LARGE_INTEGER*)&ft, 0, NULL, NULL, 0); + WaitForSingleObject(timer, ~0UL); + CloseHandle(timer); + } #else #include <sys/time.h> - static inline void cco_sleep(long msec) { - struct timeval tv = {.tv_sec=msec/1000, .tv_usec=1000*(msec % 1000)}; + static inline long long cco_utime(void) { + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec*1000000LL + tv.tv_usec; + } + + static inline void cco_usleep(long long usec) { + struct timeval tv = {.tv_sec=(time_t)(usec/1000000), .tv_usec=(suseconds_t)(usec % 1000000)}; select(0, NULL, NULL, NULL, &tv); } #endif -static inline void cco_timer_start(cco_timer* tm, long msec) { - tm->interval = msec*(CLOCKS_PER_SEC/1000); - tm->start = clock(); +typedef struct { long long interval, start; } cco_timer; + +#define cco_timer_await(...) c_MACRO_OVERLOAD(cco_timer_await, __VA_ARGS__) +#define cco_timer_await_2(tm, usec) cco_timer_await_3(tm, usec, ) +#define cco_timer_await_3(tm, usec, ret) \ + do { \ + cco_timer_start(tm, usec); \ + cco_await_2(cco_timer_expired(tm), ret); \ + } while (0) + +static inline void cco_timer_start(cco_timer* tm, long long usec) { + tm->interval = usec; + tm->start = cco_utime(); } -static inline cco_timer cco_timer_from(long msec) { - cco_timer tm = {msec*(CLOCKS_PER_SEC/1000), clock()}; +static inline cco_timer cco_timer_from(long long usec) { + cco_timer tm = {.interval=usec, .start=cco_utime()}; return tm; } static inline void cco_timer_restart(cco_timer* tm) { - tm->start = clock(); + tm->start = cco_utime(); } static inline bool cco_timer_expired(cco_timer* tm) { - return clock() - tm->start >= tm->interval; + return cco_utime() - tm->start >= tm->interval; } -static inline long cco_timer_remaining(cco_timer* tm) { - return (long)((double)(tm->start + tm->interval - clock())*(1000.0/CLOCKS_PER_SEC)); +static inline long long cco_timer_remaining(cco_timer* tm) { + return tm->start + tm->interval - cco_utime(); } #endif diff --git a/misc/examples/dining_philosophers.c b/misc/examples/dining_philosophers.c index 0bf421c6..cc6e5fd2 100644 --- a/misc/examples/dining_philosophers.c +++ b/misc/examples/dining_philosophers.c @@ -1,5 +1,6 @@ // https://en.wikipedia.org/wiki/Dining_philosophers_problem #include <stdio.h> +#include <time.h> #include <stc/crand.h> #include <stc/algo/coroutine.h> @@ -33,7 +34,7 @@ void philosopher(struct Philosopher* p) while (1) { int duration = (int)(1000 + crand() % 2000); // 1-3 seconds printf("Philosopher %d is thinking for %d minutes...\n", p->id, duration/100); - cco_timer_await(&p->tm, duration); + cco_timer_await(&p->tm, duration*1000); printf("Philosopher %d is hungry...\n", p->id); cco_sem_await(p->left_fork); @@ -41,7 +42,7 @@ void philosopher(struct Philosopher* p) duration = (int)(500 + crand() % 1000); printf("Philosopher %d is eating for %d minutes...\n", p->id, duration/100); - cco_timer_await(&p->tm, duration); + cco_timer_await(&p->tm, duration*1000); cco_sem_release(p->left_fork); cco_sem_release(p->right_fork); @@ -67,10 +68,11 @@ void dining(struct Dining* d) } while (1) { + // per-"frame" logic update of all philosophers states for (d->ph_idx = 0; d->ph_idx < num_philosophers; ++d->ph_idx) { philosopher(&d->ph[d->ph_idx]); - cco_yield(); } + cco_yield(); // suspend, return control back to main } cco_final: @@ -87,13 +89,13 @@ int main() { struct Dining dine; cco_reset(&dine); - cco_timer tm = cco_timer_from(10000); + cco_timer tm = cco_timer_from(10*1000000); // microseconds csrand((uint64_t)time(NULL)); while (!cco_done(&dine)) { if (cco_timer_expired(&tm)) cco_stop(&dine); dining(&dine); - cco_sleep(1); + cco_usleep(100); } } |
