mirror of
https://github.com/schoebel/mars
synced 2025-01-11 08:49:28 +00:00
infra: allow multiple instances of lamport clock
This commit is contained in:
parent
fddc6e491b
commit
763f17a7d8
@ -92,18 +92,21 @@
|
|||||||
*
|
*
|
||||||
* Please improve this code, but please use the right optimisation goal.
|
* Please improve this code, but please use the right optimisation goal.
|
||||||
*/
|
*/
|
||||||
struct rw_semaphore lamport_sem = __RWSEM_INITIALIZER(lamport_sem);
|
struct lamport_clock global_lamport = {
|
||||||
|
.lamport_sem = __RWSEM_INITIALIZER(global_lamport.lamport_sem),
|
||||||
|
};
|
||||||
|
EXPORT_SYMBOL_GPL(global_lamport);
|
||||||
|
|
||||||
struct lamport_time lamport_stamp = {};
|
void _get_lamport(struct lamport_clock *clock,
|
||||||
|
struct lamport_time *real_now,
|
||||||
void get_lamport(struct lamport_time *real_now, struct lamport_time *lamport_now)
|
struct lamport_time *lamport_now)
|
||||||
{
|
{
|
||||||
struct lamport_time _real_now;
|
struct lamport_time _real_now;
|
||||||
struct lamport_time _lamport_now;
|
struct lamport_time _lamport_now;
|
||||||
|
|
||||||
/* Get a consistent copy of _both_ clocks */
|
/* Get a consistent copy of _both_ clocks */
|
||||||
down_read(&lamport_sem);
|
down_read(&clock->lamport_sem);
|
||||||
_lamport_now = lamport_stamp;
|
_lamport_now = clock->lamport_stamp;
|
||||||
/* Theoretically, the next statement could be moved behind the unlock.
|
/* Theoretically, the next statement could be moved behind the unlock.
|
||||||
* However, then we will loose strictness of real timestamps,
|
* However, then we will loose strictness of real timestamps,
|
||||||
* or even may produce contradictory orderings between real and
|
* or even may produce contradictory orderings between real and
|
||||||
@ -111,7 +114,8 @@ void get_lamport(struct lamport_time *real_now, struct lamport_time *lamport_now
|
|||||||
* calls to get_lamport().
|
* calls to get_lamport().
|
||||||
*/
|
*/
|
||||||
_real_now = get_real_lamport();
|
_real_now = get_real_lamport();
|
||||||
up_read(&lamport_sem);
|
|
||||||
|
up_read(&clock->lamport_sem);
|
||||||
|
|
||||||
if (real_now)
|
if (real_now)
|
||||||
*real_now = _real_now;
|
*real_now = _real_now;
|
||||||
@ -121,58 +125,63 @@ void get_lamport(struct lamport_time *real_now, struct lamport_time *lamport_now
|
|||||||
else
|
else
|
||||||
*lamport_now = _lamport_now;
|
*lamport_now = _lamport_now;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(_get_lamport);
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(get_lamport);
|
void _set_lamport(struct lamport_clock *clock,
|
||||||
|
struct lamport_time *lamport_advance)
|
||||||
void set_lamport(struct lamport_time *lamport_old)
|
|
||||||
{
|
{
|
||||||
protect_lamport_time(lamport_old);
|
protect_lamport_time(lamport_advance);
|
||||||
|
|
||||||
/* Always advance the internal Lamport timestamp a little bit
|
/* Always advance the internal Lamport timestamp a little bit
|
||||||
* in order to ensure strict monotonicity between set_lamport() calls.
|
* in order to ensure strict monotonicity between set_lamport() calls.
|
||||||
*/
|
*/
|
||||||
down_write(&lamport_sem);
|
down_write(&clock->lamport_sem);
|
||||||
if (lamport_time_compare(lamport_old, &lamport_stamp) > 0)
|
if (lamport_time_compare(lamport_advance, &clock->lamport_stamp) > 0)
|
||||||
lamport_stamp = *lamport_old;
|
clock->lamport_stamp = *lamport_advance;
|
||||||
else
|
else
|
||||||
lamport_time_add_ns(&lamport_stamp, 1);
|
lamport_time_add_ns(&clock->lamport_stamp, 1);
|
||||||
up_write(&lamport_sem);
|
up_write(&clock->lamport_sem);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(set_lamport);
|
EXPORT_SYMBOL_GPL(_set_lamport);
|
||||||
|
|
||||||
void set_lamport_nonstrict(struct lamport_time *lamport_old)
|
void _set_lamport_nonstrict(struct lamport_clock *clock,
|
||||||
|
struct lamport_time *lamport_advance)
|
||||||
{
|
{
|
||||||
protect_lamport_time(lamport_old);
|
protect_lamport_time(lamport_advance);
|
||||||
|
|
||||||
/* Speculate that advaning is not necessary, to avoid the lock
|
/* Speculate that advaning is not necessary, to avoid the lock
|
||||||
*/
|
*/
|
||||||
if (lamport_time_compare(lamport_old, &lamport_stamp) > 0) {
|
if (lamport_time_compare(lamport_advance, &clock->lamport_stamp) > 0) {
|
||||||
down_write(&lamport_sem);
|
down_write(&clock->lamport_sem);
|
||||||
if (lamport_time_compare(lamport_old, &lamport_stamp) > 0)
|
if (lamport_time_compare(lamport_advance, &clock->lamport_stamp) > 0)
|
||||||
lamport_stamp = *lamport_old;
|
clock->lamport_stamp = *lamport_advance;
|
||||||
up_write(&lamport_sem);
|
up_write(&clock->lamport_sem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(set_lamport_nonstrict);
|
EXPORT_SYMBOL_GPL(_set_lamport_nonstrict);
|
||||||
|
|
||||||
/* After advancing the Lamport time, re-get the new values.
|
/* After advancing the Lamport time, re-get the new values.
|
||||||
* This is almost equivalent to a sequence of set_lamport() ; get_lamport()
|
* This is almost equivalent to a sequence of set_lamport() ; get_lamport()
|
||||||
* but more efficient because the lock is taken only once.
|
* but more efficient because the lock is taken only once.
|
||||||
*/
|
*/
|
||||||
void set_get_lamport(struct lamport_time *lamport_old, struct lamport_time *real_now, struct lamport_time *lamport_now)
|
void _set_get_lamport(struct lamport_clock *clock,
|
||||||
|
struct lamport_time *lamport_advance,
|
||||||
|
struct lamport_time *real_now,
|
||||||
|
struct lamport_time *lamport_now)
|
||||||
{
|
{
|
||||||
struct lamport_time _real_now;
|
struct lamport_time _real_now;
|
||||||
|
|
||||||
protect_lamport_time(lamport_old);
|
protect_lamport_time(lamport_advance);
|
||||||
|
|
||||||
down_write(&lamport_sem);
|
down_write(&clock->lamport_sem);
|
||||||
if (lamport_time_compare(lamport_old, &lamport_stamp) > 0)
|
if (lamport_time_compare(lamport_advance, &clock->lamport_stamp) > 0)
|
||||||
*lamport_now = *lamport_old;
|
*lamport_now = *lamport_advance;
|
||||||
else
|
else
|
||||||
*lamport_now = lamport_time_add(lamport_stamp, (struct lamport_time){0, 1});
|
*lamport_now = lamport_time_add(clock->lamport_stamp,
|
||||||
lamport_stamp = *lamport_now;
|
(struct lamport_time){0, 1});
|
||||||
|
clock->lamport_stamp = *lamport_now;
|
||||||
_real_now = get_real_lamport();
|
_real_now = get_real_lamport();
|
||||||
up_write(&lamport_sem);
|
up_write(&clock->lamport_sem);
|
||||||
|
|
||||||
if (real_now)
|
if (real_now)
|
||||||
*real_now = _real_now;
|
*real_now = _real_now;
|
||||||
@ -180,27 +189,30 @@ void set_get_lamport(struct lamport_time *lamport_old, struct lamport_time *real
|
|||||||
if (lamport_time_compare(&_real_now, lamport_now) > 0)
|
if (lamport_time_compare(&_real_now, lamport_now) > 0)
|
||||||
*lamport_now = _real_now;
|
*lamport_now = _real_now;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(set_get_lamport);
|
EXPORT_SYMBOL_GPL(_set_get_lamport);
|
||||||
|
|
||||||
/* Protect against illegal values, e.g. from currupt filesystems etc.
|
/* Protect against illegal values, e.g. from currupt filesystems etc.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int max_lamport_future = 30 * 24 * 3600;
|
int max_lamport_future = 30 * 24 * 3600;
|
||||||
|
|
||||||
bool protect_lamport_time(struct lamport_time *check)
|
bool _protect_lamport_time(struct lamport_clock *clock,
|
||||||
|
struct lamport_time *check)
|
||||||
{
|
{
|
||||||
struct lamport_time limit = get_real_lamport();
|
struct lamport_time limit = get_real_lamport();
|
||||||
bool res = false;
|
bool res = false;
|
||||||
|
|
||||||
limit.tv_sec += max_lamport_future;
|
limit.tv_sec += max_lamport_future;
|
||||||
if (unlikely(check->tv_sec >= limit.tv_sec)) {
|
if (unlikely(check->tv_sec >= limit.tv_sec)) {
|
||||||
down_write(&lamport_sem);
|
down_write(&clock->lamport_sem);
|
||||||
lamport_time_add_ns(&lamport_stamp, 1);
|
lamport_time_add_ns(&clock->lamport_stamp, 1);
|
||||||
memcpy(check, &lamport_stamp, sizeof(*check));
|
lamport_time_add_ns(&clock->lamport_stamp, 1);
|
||||||
|
memcpy(check, &clock->lamport_stamp, sizeof(*check));
|
||||||
if (unlikely(check->tv_sec > limit.tv_sec))
|
if (unlikely(check->tv_sec > limit.tv_sec))
|
||||||
max_lamport_future += check->tv_sec - limit.tv_sec;
|
max_lamport_future += check->tv_sec - limit.tv_sec;
|
||||||
up_write(&lamport_sem);
|
up_write(&clock->lamport_sem);
|
||||||
res = true;
|
res = true;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(_protect_lamport_time);
|
||||||
|
@ -53,6 +53,19 @@
|
|||||||
# define get_real_lamport() CURRENT_TIME
|
# define get_real_lamport() CURRENT_TIME
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <linux/rwsem.h>
|
||||||
|
|
||||||
|
struct lamport_clock {
|
||||||
|
struct rw_semaphore lamport_sem;
|
||||||
|
struct lamport_time lamport_stamp;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct lamport_clock global_lamport;
|
||||||
|
|
||||||
|
/* Protect against illegal values, e.g. from currupt filesystems etc.
|
||||||
|
*/
|
||||||
|
extern int max_lamport_future;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We always get both the local real time and the Lamport time in parallel,
|
* We always get both the local real time and the Lamport time in parallel,
|
||||||
* consistently.
|
* consistently.
|
||||||
@ -62,30 +75,92 @@
|
|||||||
*
|
*
|
||||||
* When not interested in real time, you can simply leave real_now at NULL.
|
* When not interested in real time, you can simply leave real_now at NULL.
|
||||||
*/
|
*/
|
||||||
extern void get_lamport(struct lamport_time *real_now,
|
extern void _get_lamport(struct lamport_clock *clock,
|
||||||
|
struct lamport_time *real_now,
|
||||||
struct lamport_time *lamport_now);
|
struct lamport_time *lamport_now);
|
||||||
|
|
||||||
/* This ensures _strict_ monotonicity of the Lamport clock */
|
/* This ensures _strict_ monotonicity of the Lamport clock */
|
||||||
extern void set_lamport(struct lamport_time *lamport_old);
|
extern void _set_lamport(struct lamport_clock *clock,
|
||||||
|
struct lamport_time *lamport_advance);
|
||||||
|
|
||||||
/* Non-strict version.
|
/* Non-strict version.
|
||||||
* Use this for better performance when strictness is not needed.
|
* Use this for better performance when strictness is not needed.
|
||||||
*/
|
*/
|
||||||
extern void set_lamport_nonstrict(struct lamport_time *lamport_old);
|
extern void _set_lamport_nonstrict(struct lamport_clock *clock,
|
||||||
|
struct lamport_time *lamport_advance);
|
||||||
|
|
||||||
/* After strictly advancing the Lamport time, re-get the new values.
|
/* After strictly advancing the Lamport time, re-get the new values.
|
||||||
* This is almost equivalent to a sequence of set_lamport() ; get_lamport()
|
* This is almost equivalent to a sequence of set_lamport() ; get_lamport()
|
||||||
* but (1) atomic and (2) more efficient
|
* but (1) atomic and (2) more efficient
|
||||||
* because the internal lock is taken only once.
|
* because the internal lock is taken only once.
|
||||||
*/
|
*/
|
||||||
extern void set_get_lamport(struct lamport_time *lamport_old,
|
extern void _set_get_lamport(struct lamport_clock *clock,
|
||||||
|
struct lamport_time *lamport_advance,
|
||||||
struct lamport_time *real_now,
|
struct lamport_time *real_now,
|
||||||
struct lamport_time *lamport_now);
|
struct lamport_time *lamport_now);
|
||||||
|
|
||||||
/* Protect against illegal values, e.g. from currupt filesystems etc.
|
extern bool _protect_lamport_time(struct lamport_clock *clock,
|
||||||
*/
|
struct lamport_time *check);
|
||||||
extern int max_lamport_future;
|
|
||||||
|
|
||||||
extern bool protect_lamport_time(struct lamport_time *check);
|
|
||||||
|
/* Usually the following versions are the preferred ones for working
|
||||||
|
* on the single global lamport clock instance.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define get_lamport(real_now,lamport_now) \
|
||||||
|
_get_lamport(&global_lamport,real_now,lamport_now)
|
||||||
|
|
||||||
|
#define set_lamport(lamport_advance) \
|
||||||
|
_set_lamport(&global_lamport,lamport_advance)
|
||||||
|
|
||||||
|
#define set_lamport_nonstrict(lamport_advance) \
|
||||||
|
_set_lamport_nonstrict(&global_lamport,lamport_advance)
|
||||||
|
|
||||||
|
#define set_get_lamport(lamport_advance,real_now,lamport_now) \
|
||||||
|
_set_get_lamport(&global_lamport,lamport_advance,real_now,lamport_now)
|
||||||
|
|
||||||
|
#define protect_lamport_time(check) \
|
||||||
|
_protect_lamport_time(&global_lamport,check)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Here is a very general lockless version for inlining.
|
||||||
|
* Typical usage is when no true concurrency can happen, or when
|
||||||
|
* some other embracing locks are already protecting the scene.
|
||||||
|
* All pointers except clock may be NULL, then no code
|
||||||
|
* will be generated.
|
||||||
|
*/
|
||||||
|
static inline
|
||||||
|
void __lamport_op(struct lamport_time *clock,
|
||||||
|
struct lamport_time *lamport_prev,
|
||||||
|
struct lamport_time *lamport_advance,
|
||||||
|
struct lamport_time *real_now,
|
||||||
|
struct lamport_time *lamport_now)
|
||||||
|
{
|
||||||
|
/* Remember the old clock value. */
|
||||||
|
if (lamport_prev)
|
||||||
|
*lamport_prev = *clock;
|
||||||
|
|
||||||
|
/* Advance the clock when necessary. */
|
||||||
|
if (lamport_advance)
|
||||||
|
if (lamport_time_compare(lamport_advance, clock) > 0)
|
||||||
|
*clock = *lamport_advance;
|
||||||
|
else
|
||||||
|
*clock = lamport_time_add(*clock,
|
||||||
|
(struct lamport_time){0, 1});
|
||||||
|
else
|
||||||
|
*clock = lamport_time_add(*clock,
|
||||||
|
(struct lamport_time){0, 1});
|
||||||
|
|
||||||
|
/* Get and handle realtime */
|
||||||
|
if (real_now) {
|
||||||
|
*real_now = get_real_lamport();
|
||||||
|
if (lamport_time_compare(real_now, clock) > 0)
|
||||||
|
*clock = *real_now;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Finally, retrieve new lamport stamp */
|
||||||
|
if (lamport_now)
|
||||||
|
*lamport_now = *clock;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user