Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/subr_smr.c
Show First 20 Lines • Show All 203 Lines • ▼ Show 20 Lines | smr_advance(smr_t smr) | ||||
* wrap detecting arithmetic working in pathological cases. | * wrap detecting arithmetic working in pathological cases. | ||||
*/ | */ | ||||
if (goal - atomic_load_int(&s->s_rd_seq) >= SMR_SEQ_MAX_DELTA) | if (goal - atomic_load_int(&s->s_rd_seq) >= SMR_SEQ_MAX_DELTA) | ||||
smr_wait(smr, goal - SMR_SEQ_MAX_ADVANCE); | smr_wait(smr, goal - SMR_SEQ_MAX_ADVANCE); | ||||
return (goal); | return (goal); | ||||
} | } | ||||
smr_seq_t | |||||
smr_advance_deferred(smr_t smr, int limit) | |||||
{ | |||||
smr_seq_t goal; | |||||
smr_t csmr; | |||||
critical_enter(); | |||||
csmr = zpcpu_get(smr); | |||||
if (++csmr->c_deferred >= limit) { | |||||
goal = SMR_SEQ_INVALID; | |||||
csmr->c_deferred = 0; | |||||
} else | |||||
goal = smr_shared_current(csmr->c_shared) + SMR_SEQ_INCR; | |||||
critical_exit(); | |||||
if (goal != SMR_SEQ_INVALID) | |||||
rlibby: Micro-opt: maybe consider this, in order to have one well-predicted branch? I think the… | |||||
return (goal); | |||||
return (smr_advance(smr)); | |||||
} | |||||
/* | /* | ||||
* Poll to determine whether all readers have observed the 'goal' write | * Poll to determine whether all readers have observed the 'goal' write | ||||
* sequence number. | * sequence number. | ||||
* | * | ||||
* If wait is true this will spin until the goal is met. | * If wait is true this will spin until the goal is met. | ||||
* | * | ||||
* This routine will updated the minimum observed read sequence number in | * This routine will updated the minimum observed read sequence number in | ||||
* s_rd_seq if it does a scan. It may not do a scan if another call has | * s_rd_seq if it does a scan. It may not do a scan if another call has | ||||
Show All 30 Lines | smr_poll(smr_t smr, smr_seq_t goal, bool wait) | ||||
*/ | */ | ||||
s_rd_seq = atomic_load_acq_int(&s->s_rd_seq); | s_rd_seq = atomic_load_acq_int(&s->s_rd_seq); | ||||
/* | /* | ||||
* wr_seq must be loaded prior to any c_seq value so that a stale | * wr_seq must be loaded prior to any c_seq value so that a stale | ||||
* c_seq can only reference time after this wr_seq. | * c_seq can only reference time after this wr_seq. | ||||
*/ | */ | ||||
s_wr_seq = atomic_load_acq_int(&s->s_wr_seq); | s_wr_seq = atomic_load_acq_int(&s->s_wr_seq); | ||||
/* | |||||
* This may have come from a deferred advance. Consider one | |||||
rlibbyUnsubmitted Not Done Inline ActionsI think this would read more clearly with s/This/The goal/. rlibby: I think this would read more clearly with s/This/The goal/. | |||||
* increment past the current wr_seq valid and make sure we | |||||
* have advanced far enough to succeed. | |||||
*/ | |||||
if (goal == s_wr_seq + SMR_SEQ_INCR) | |||||
s_wr_seq = atomic_fetchadd_int(&s->s_wr_seq, | |||||
jeffAuthorUnsubmitted Done Inline ActionsI think this now suffers from the same problem that required the acq barrier above. Perhaps I can do an unfenced load on wr-seq then a thread_fence_acq() after this check. jeff: I think this now suffers from the same problem that required the acq barrier above.
Perhaps I… | |||||
rlibbyUnsubmitted Not Done Inline ActionsYou've also already done a fetch above, so I think you could just atomic_add_acq() here and then increment the local s_wr_seq. A slightly stale s_wr_seq must not be a problem, because you can be racing with another cpu anyway. However, I think this might be a little better as atomic_cmpset_acq, because you don't really care to add here, you really want atomic_max(). But since you know that the clock always ticks forward, cmpset yields a max. rlibby: You've also already done a fetch above, so I think you could just atomic_add_acq() here and… | |||||
SMR_SEQ_INCR) + SMR_SEQ_INCR; | |||||
/* | /* | ||||
* Detect whether the goal is valid and has already been observed. | * Detect whether the goal is valid and has already been observed. | ||||
* | * | ||||
* The goal must be in the range of s_wr_seq >= goal >= s_rd_seq for | * The goal must be in the range of s_wr_seq >= goal >= s_rd_seq for | ||||
* it to be valid. If it is not then the caller held on to it and | * it to be valid. If it is not then the caller held on to it and | ||||
* the integer wrapped. If we wrapped back within range the caller | * the integer wrapped. If we wrapped back within range the caller | ||||
* will harmlessly scan. | * will harmlessly scan. | ||||
▲ Show 20 Lines • Show All 132 Lines • Show Last 20 Lines |
Micro-opt: maybe consider this, in order to have one well-predicted branch? I think the compiler can't reduce the double branch otherwise, due to the compiler barrier in critical_exit().