blob: bc815279de418a88e8f9871af717cfb3c8343db2 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//
// A weakref is initialized with an epoch number and an index.
//
// The epoch number is assumed to never roll over and therefore be
// unique for the life of the Spinel context.
//
// Details:
//
// V1 V2*
// 0 63 0 63
// | INDEX | EPOCH | | INDEX | EPOCH |
// +-------+-------+ +-------+-------+
// | ~13 | ~51 | | 8 | 56 |
//
// (* V2 forthcoming and uses only 8 bits for .index )
//
// Frequency of epoch increments determines how long it takes to a
// fatal rollover:
//
// 13:51 bits 8:56 bits
// +------+-----------+ +------+------------+
// | Hz | Years | | Hz | Years |
// +------+-----------+ +------+------------+
// | 60 | 1,189,279 | | 60 | 38,056,935 |
// | 1000 | 71,356 | | 1000 | 2,283,416 |
// | 5000 | 14,271 | | 5000 | 456,683 |
//
// Epochs are incremented in the path and raster builder ring buffers
// and probably can't be updated faster than a 1000 Hz.
//
#include "weakref.h"
#include <stdlib.h>
#include "common/macros.h"
#include "core_c.h"
//
// Weakref bit allocation
//
// clang-format off
#define SPN_WEAKREF_INDEX_BITS 13 // max bits for a weakref index
#define SPN_WEAKREF_INDEX_COUNT (1 << SPN_WEAKREF_INDEX_BITS)
#define SPN_WEAKREF_LO_INDEX_MASK BITS_TO_MASK_MACRO(SPN_WEAKREF_INDEX_BITS)
#define SPN_WEAKREF_EPOCH_LO_MASK BITS_TO_MASK_AT_MACRO(32 - SPN_WEAKREF_INDEX_BITS, SPN_WEAKREF_INDEX_BITS)
#define SPN_WEAKREF_EPOCH_LO_ONE SPN_WEAKREF_INDEX_COUNT
// clang-format on
//
// Compile-time guards listed here:
//
STATIC_ASSERT_MACRO_1(SPN_WEAKREF_INDEX_BITS >= SPN_TTRK_HI_BITS_COHORT); // TTRK.RASTER_COHORT_ID
//
// Epoch starts at { .epoch = 0 }
//
// 0 63
// | N/A | EPOCH |
// +-------+-------+
// | ~13 | ~51 |
//
void
spinel_weakref_epoch_init(spinel_weakref_epoch_t * epoch)
{
*epoch = (spinel_weakref_epoch_t){ 0, 0 };
}
//
// Note that using multiprecision arithmetic intrinsics generates
// worse code because we're only incrementing by 1.
//
void
spinel_weakref_epoch_increment(spinel_weakref_epoch_t * epoch)
{
epoch->epoch[0] += SPN_WEAKREF_EPOCH_LO_ONE;
if (epoch->epoch[0] == 0)
{
epoch->epoch[1] += 1;
}
}
//
//
//
static void
spinel_weakref_init(uint32_t weakref[2], spinel_weakref_epoch_t const * epoch, uint32_t const index)
{
assert(index < SPN_WEAKREF_INDEX_COUNT);
weakref[0] = epoch->epoch[0] | index;
weakref[1] = epoch->epoch[1];
}
static bool
spinel_weakref_get_index(uint32_t const weakref[2],
spinel_weakref_epoch_t const * epoch,
uint32_t * index)
{
// test lo
if (((weakref[0] ^ epoch->epoch[0]) & SPN_WEAKREF_EPOCH_LO_MASK) != 0)
{
return false;
}
// test hi
if (weakref[1] != epoch->epoch[1])
{
return false;
}
// weakref wasn't refuted
*index = weakref[0] & SPN_WEAKREF_LO_INDEX_MASK;
return true;
}
//
//
//
void
spinel_transform_weakrefs_init(spinel_transform_weakref_t * weakrefs,
uint32_t const offset,
spinel_weakref_epoch_t const * epoch,
uint32_t const index)
{
if (weakrefs == NULL)
return;
spinel_transform_weakref_t * weakref = weakrefs + offset;
spinel_weakref_init(weakref->weakref, epoch, index);
}
bool
spinel_transform_weakrefs_get_index(spinel_transform_weakref_t const * weakrefs,
uint32_t const offset,
spinel_weakref_epoch_t const * epoch,
uint32_t * index)
{
if (weakrefs == NULL)
return false;
spinel_transform_weakref_t const * weakref = weakrefs + offset;
return spinel_weakref_get_index(weakref->weakref, epoch, index);
}
//
//
//
void
spinel_clip_weakrefs_init(spinel_clip_weakref_t * weakrefs,
uint32_t const offset,
spinel_weakref_epoch_t const * epoch,
uint32_t const index)
{
if (weakrefs == NULL)
return;
spinel_clip_weakref_t * weakref = weakrefs + offset;
spinel_weakref_init(weakref->weakref, epoch, index);
}
bool
spinel_clip_weakrefs_get_index(spinel_clip_weakref_t const * weakrefs,
uint32_t const offset,
spinel_weakref_epoch_t const * epoch,
uint32_t * index)
{
if (weakrefs == NULL)
return false;
spinel_clip_weakref_t const * weakref = weakrefs + offset;
return spinel_weakref_get_index(weakref->weakref, epoch, index);
}
//
//
//