blob: 4652277ea04fc6967c43f03933179f28b2ee5b93 [file] [log] [blame]
// Copyright 2018 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.
#ifndef GARNET_LIB_MEDIA_CODEC_IMPL_INCLUDE_LIB_MEDIA_CODEC_IMPL_CODEC_ADMISSION_CONTROL_H_
#define GARNET_LIB_MEDIA_CODEC_IMPL_INCLUDE_LIB_MEDIA_CODEC_IMPL_CODEC_ADMISSION_CONTROL_H_
#include <lib/async/cpp/task.h>
#include <lib/fit/function.h>
#include <zircon/compiler.h>
#include <mutex>
#include <fbl/macros.h>
// Controls how many Codec instances are concurrently served by this process.
//
// There's a limit of 1 for single-instance decoders, but arbitrarily-many
// multi-instance decoders can be used if there's no single-instance decoder.
class CodecAdmission;
class CodecAdmissionControl {
public:
// Create with a dispatcher to post async calls to the shared fidl thread.
explicit CodecAdmissionControl(async_dispatcher_t* shared_fidl_dispatcher);
// Get a move-only CodecAdmission as a move-only ticket that allows creation
// of a CodecImpl.
//
// TODO(dustingreen): The attempt to add a codec should not be started until
// after any previously-initiated Codec channel closes are fully done being
// processed. This method signature allows for that fencing to be added later
// without changing the call site, but the actual fencing isn't really there
// yet - currently a single re-post is done to make the async-ness real, but
// (at least) because close processing itself needs to post around to get
// everything shut down cleanly, the overall fencing isn't really there yet.
//
// TODO(dustingreen): std::optional<> instead when C++17.
void TryAddCodec(bool multi_instance,
fit::function<void(std::unique_ptr<CodecAdmission>)>
continue_after_previously_started_channel_closes_done);
// Anything posted here will run after any previously-posted items here or via
// TryAddCodec().
//
// Run the posted closure after all previously-started closes are done being
// processed, and after all previously-queued closures via this method are
// done.
//
// TODO(dustingreen): This doesn't actually do what it says yet, though
// items queued via this method and TryAddCodec() do run in order.
void PostAfterPreviouslyStartedClosesDone(fit::closure to_run);
private:
friend class CodecAdmission;
// This is called after exactly one post via
// PostAfterPreviouslyStartedClosesDone() performed by TryAddCodec().
std::unique_ptr<CodecAdmission> TryAddCodecInternal(bool multi_instance);
void RemoveCodec(bool multi_instance);
async_dispatcher_t* shared_fidl_dispatcher_;
std::mutex lock_;
uint32_t single_instance_codec_count_ __TA_GUARDED(lock_);
uint32_t multi_instance_codec_count_ __TA_GUARDED(lock_);
DISALLOW_COPY_ASSIGN_AND_MOVE(CodecAdmissionControl);
};
class CodecAdmission {
public:
// move-only
//
// These user-declared but not user-provided move construct / move assign
// still count as user-delcared, so these (either of them) cause normal copy
// and assign to be implicitly deleted (both of them).
CodecAdmission(CodecAdmission&& from) = default;
CodecAdmission& operator=(CodecAdmission&& from) = default;
~CodecAdmission();
private:
friend class CodecAdmissionControl;
CodecAdmission(CodecAdmissionControl* codec_admission_control,
bool multi_instance);
CodecAdmissionControl* codec_admission_control_ = nullptr;
bool multi_instance_;
};
#endif // GARNET_LIB_MEDIA_CODEC_IMPL_INCLUDE_LIB_MEDIA_CODEC_IMPL_CODEC_ADMISSION_CONTROL_H_