template <typename TrackedType, typename HolderType, size_t user_tag_bits = 4u>

class ObjectTracker

Defined at line 143 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

ObjectTracker is a a kernel version of a multithreaded map container + allocator

specialized for uint32

<

--> object. It provides the standard map services

add, remove, get

&

enumerate but also the storage services of a pool allocator.

ObjectTracker fills the gap between the existing helpers:

- allocators cannot enumerate their live objects, the current solution is

to use a intrusive linked list to enumerate them which comes with 16 bytes

overhead and lookups are O(n).

- The WAVL tree supports fast lookups and iteration but each object must

pay 48+ bytes overhead, so it is only practical if the object weights upwards of

200 bytes.

The API is move-oriented, the typical lifecycle goes:

1 - Create object |o| to be tracked

2 - Move |o| into the tracker via add(o) which returns its |id|.

3 - Retrieve the object reference (via the holder) from get(id)

4 - call |o| methods via the holder

5 - Drop the holder

6 - Either remove the object from tracking via remove(id) or

goto step 3.

Using it

ObjectTracker takes two class template parameters:

A) TrackedType: the class to be stored and tracked, it must implement three

methods:

1- zx_status on_holder(uint32_t user_tag). Called when a Holder needs to

be created. If this method returns an error, the holder will not be

created and the error will be returned instead.

2- uint32_t on_tracked(). Called once the object is being tracked. The

returned value is the "user tag" included in the tracking id. See remarks

below.

3- zx_status_t on_remove(uint32_t user_tag). Called before is removed from

tracking. If this method returns an error, the object will not be removed

from the container and the error will be returned instead.

If the user_tag feature is not needed, on_tracked() and on_remove() methods can

have a no-op implementations as follows:

uint32_t on_tracked() {

return 0u;

}

zx_status_t on_remove(uint32_t) {

return ZX_OK;

}

All the above callbacks are issued with a spinlock acquired that protects the page

where the tracked object lives. Therefore, no calls to the tracker should be issued

from the callback or calls that acquire regular mutexes. Calls that acquire

spinlocks are ok.

B) HolderType: an object of this class is returned when ObjectTracker::get()

is successful. The Holder is created via the HolderType(TrackedType

&

) or the

HolderType(const TrackedType

&

) ctor. If HolderType keeps a weak reference to the

TrackedType then it must collaborate with it to prevent ObjectTracker::remove()

from succeeding by returning an error from TrackedType::on_remove().

The TrackedType has one more requirement: it must have a boring destructor

for the particular case when it is called for a moved-from state. In other words

assume a TrackedType = TFoo, then

TFoo destination;

{

// stack allocated storage for |source|.

alignas(Foo) char data[sizeof(Foo)];

TFoo* source = new (data) TFoo();

......

......

destination = std::move(*source);

avoid_dtor = true;

if (!avoid_dtor) {

source->~TFoo();

}

}

The program above is correct for the TFoo type. Note that if TFoo is not in the

moved-from state, the destructor can do all sorts of critical operations, this means

the object tracker that fail the ktl::is_trivially_destructible

<TrackedType

> test.

Using the user_tag

A user tag is a small value, cookie-like, with as many bits as the template parameter

user_tag_bits. It is provided by the tracked object during ObjectTracker::add() via the

callback on_tracked() and returned as mixed in the returned id. This tag is given back

to the tracked object during the ObjectTracker::get() in the on_holder()

callback or during ObjectTracker::remove() in the on_remove() callback.

The tracked object has full freedom how to interpret the tag, it might require to be

provided back the same tag or a different value. The ObjectTracker::encode() and

decode() static functions can be used by clients to extract or replace the tag returned

by the tracked object, except in one case, during the ObjectTracker destruction

or if triggered manually via destroy_all() the on_remove() callback is issued with

the special value kTagDestroy, which is hardcoded to be the highest value possible

for an unsigned number of size user_tag_bits.

Public Members

static const uint32_t kTagDestroy

Public Methods

void ObjectTracker<TrackedType, HolderType, user_tag_bits> ()

Defined at line 145 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

void ObjectTracker<TrackedType, HolderType, user_tag_bits> (const ObjectTracker<TrackedType, HolderType, user_tag_bits> & )

Defined at line 146 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

void ObjectTracker<TrackedType, HolderType, user_tag_bits> (ObjectTracker<TrackedType, HolderType, user_tag_bits> && )

Defined at line 147 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

void ObjectTracker<TrackedType, HolderType, user_tag_bits> (page_cache::PageCache * page_cache)

Defined at line 149 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

void ~ObjectTracker<TrackedType, HolderType, user_tag_bits> ()

Defined at line 150 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

uint32_t obs_per_page ()

How many objects fit in a page. Only interesting if you are also using

encode() or decode(), or deeply care about efficient storage.

Defined at line 228 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

uint32_t max_pages ()

Ids are uint32_t and must fit the index, tag and, page id which limits

the number of pages.

Defined at line 232 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

zx::result<HolderType> get (uint32_t id)

Make a holder from a tracked object pointed by |id|. The only error possible is

ZX_ERR_NOT_FOUND. Otherwise an HolderType is returned.

Defined at line 564 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

zx_status_t get (ktl::span<const uint32_t> ids, ktl::span<HolderType> holders)

Batch-get. Same considerations as the single-issue get apply.

Defined at line 578 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

zx::result<uint32_t> add (TrackedType object)

Move the |object| into the tracker. The only error results are the ones returned

by PageCache, which are memory related: ZX_ERR_OUT_OF_MEMORY or ZX_ERR_OUT_OF_RANGE

if we have maxed out the number of pages that can be allocated. Otherwise the result is

the id of the object.

Because of the locking scheme, It is possible for another thread guessing ids to issue a

successful get() and operate on the |object| before this method returns. In other words

the object moved (or copied) from |object| can start receiving method calls before this

method returns but after it has been fully created.

Defined at line 599 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

zx_status_t add (ktl::span<TrackedType> objects, ktl::span<uint32_t> ids)

Move the |objects| into the tracker returning their assigned ids in |ids|.

The possible errors are the same as the single item Add(). In the case of an error

some elements might have been inserted already. If the user wants to recover from this

it is recommended that the output |ids| vector should contain zeros so if desired the

newly inserted objects might be removed.

Defined at line 630 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

zx::result<TrackedType> remove (uint32_t id)

Remove the (previously added) object from tracking. There are two

main error conditions:

- ZX_ERR_NOT_FOUND: the |id| does not correspond to an tracked object.

- The object does not want to be removed, that is, on_remove() returned an

error which is returned here. It might be that an alive HolderType object

is preventing the removal.

Defined at line 706 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

zx_status_t remove (ktl::span<const uint32_t> ids, ktl::span<TrackedType> objects)

Remove the previously added objects in |ids| and returns them in |objects|.

The input array is mutated.

In the case of failure, for example one of the ids is invalid, the rest are still

processed. This means that there are two outcomes:

- success: all objects are in the output vector

- failure: all objects that could be removed are destroyed.

Defined at line 730 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

size_t destroy_all ()

Destroy all the tracked objects.

This method is to be called when by construction you know that there are no outstanding

HolderType objects. It will remove (or assert if it can't) all the tracked objects and

call the destructors to each one.

Also beware that it will hold internal spinlocks so you want to make sure other threads

are not going to be adding or removing objects to the tracker concurrently.

Defined at line 751 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

size_t count_slow ()

Returns how many objects are being tracked. Only use this method

for testing.

Defined at line 776 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

size_t page_count ()

Returns how many pages are being used. You can use this method for

testing or for in-the-field memory diagnostics.

Defined at line 786 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

auto decode (uint32_t id)

Decodes an |id| returned by add() so the client can store the

id differently. For example if the number of objects is limited

by other means, an id can be compressed into 16 bits.

Defined at line 976 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

uint32_t encode (uint32_t page_id, uint32_t index, uint32_t user_tag)

Encodes the tuple returned by decode() back into a tracker id. Only

needed if you use decode() and store the id in an interesting way.

Defined at line 990 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

uint32_t encode (uint32_t page_id, uint32_t index_and_tag)

Like encode but for a pre-combined index plus tag.

Defined at line 998 of file ../../zircon/kernel/lib/fbl/include/fbl/object_tracker.h

Records