log.cpp
polling_filesystem_monitor.cpp
stdafx.cpp
+ thread_info.cpp
tweener.cpp
utf.cpp
)
os/windows/filesystem.cpp
os/windows/page_locked_allocator.cpp
os/windows/prec_timer.cpp
- os/windows/scheduling.cpp
+ os/windows/threading.cpp
os/windows/stack_trace.cpp
os/windows/system_info.cpp
os/windows/win32_exception.cpp
os/linux/filesystem.cpp
os/linux/prec_timer.cpp
os/linux/signal_handlers.cpp
- os/linux/scheduling.cpp
+ os/linux/threading.cpp
os/linux/stack_trace.cpp
os/linux/system_info.cpp
)
os/filesystem.h
os/general_protection_fault.h
os/page_locked_allocator.h
- os/scheduling.h
+ os/threading.h
os/stack_trace.h
os/system_info.h
scope_exit.h
semaphore.h
stdafx.h
+ thread_info.h
timer.h
tweener.h
utf.h
#include "../../except.h"
#include "../../log.h"
+#include "../../thread_info.h"
#include <signal.h>
const char* thread_description)
{
static auto install = []() { do_install_handlers(); return 0; } ();
+
+ if (thread_description)
+ get_thread_info().name = thread_description;
}
}
#include "../../stdafx.h"
-#include "../scheduling.h"
+#include "../threading.h"
namespace caspar {
-
+
void set_priority_of_current_thread(thread_priority priority)
{
// TODO: implement
}
+std::int64_t get_current_thread_id()
+{
+ // TODO: implement
+ return 0;
+}
+
}
#pragma once
+#include <cstdint>
+
namespace caspar {
enum class thread_priority
};
void set_priority_of_current_thread(thread_priority priority);
+std::int64_t get_current_thread_id();
}
#include "../../stdafx.h"
-#include "../scheduling.h"
+#include "../threading.h"
#include "windows.h"
SetThreadPriority(GetCurrentThread(), BELOW_NORMAL_PRIORITY_CLASS);
}
+std::int64_t get_current_thread_id()
+{
+ return GetCurrentThreadId();
+}
+
}
#include <boost/thread.hpp>
+#include "../../thread_info.h"
#include "windows.h"
namespace caspar { namespace detail {
install_gpf_handler();
if (thread_description)
+ {
detail::SetThreadName(GetCurrentThreadId(), thread_description);
+ get_thread_info().name = thread_description;
+ }
}
}
--- /dev/null
+/*
+* Copyright 2013 Sveriges Television AB http://casparcg.com/
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Helge Norberg, helge.norberg@svt.se
+*/
+
+#include "stdafx.h"
+
+#include "thread_info.h"
+#include "os/threading.h"
+
+#include <map>
+
+#include <boost/thread/tss.hpp>
+#include <boost/thread/mutex.hpp>
+#include <boost/thread/lock_guard.hpp>
+#include <boost/lexical_cast.hpp>
+
+namespace caspar {
+
+class enumerable_thread_infos
+{
+ boost::mutex mutex_;
+ std::map<void*, std::weak_ptr<thread_info>> enumerable_;
+ boost::thread_specific_ptr<std::shared_ptr<thread_info>> infos_;
+public:
+ static enumerable_thread_infos& get_instance()
+ {
+ static enumerable_thread_infos instance;
+
+ return instance;
+ }
+
+ std::vector<spl::shared_ptr<thread_info>> get_thread_infos()
+ {
+ boost::lock_guard<boost::mutex> lock(mutex_);
+
+ std::vector<spl::shared_ptr<thread_info>> result;
+ result.reserve(enumerable_.size());
+
+ for (auto it = enumerable_.begin(); it != enumerable_.end();)
+ {
+ auto lock = it->second.lock();
+
+ if (lock)
+ {
+ result.push_back(spl::make_shared_ptr(lock));
+ ++it;
+ }
+ else
+ {
+ it = enumerable_.erase(it);
+ }
+ }
+
+ std::sort(result.begin(), result.end(), [](const spl::shared_ptr<thread_info>& lhs, const spl::shared_ptr<thread_info>& rhs) { return lhs->native_id < rhs->native_id; });
+
+ return result;
+ }
+
+ thread_info& get_thread_info()
+ {
+ auto local = infos_.get();
+
+ if (!local)
+ {
+ std::unique_ptr<thread_info> p(new thread_info);
+ local = new std::shared_ptr<thread_info>(p.get(), [this](thread_info* p)
+ {
+ boost::lock_guard<boost::mutex> lock(mutex_);
+ enumerable_.erase(p);
+ delete p;
+ });
+ p.release();
+ infos_.reset(local);
+ boost::lock_guard<boost::mutex> lock(mutex_);
+ enumerable_.insert(std::make_pair(local->get(), *local));
+ }
+
+ return **local;
+ }
+};
+
+thread_info::thread_info()
+ : native_id(get_current_thread_id())
+{
+}
+
+thread_info& get_thread_info()
+{
+ return enumerable_thread_infos::get_instance().get_thread_info();
+}
+
+std::vector<spl::shared_ptr<thread_info>> get_thread_infos()
+{
+ return enumerable_thread_infos::get_instance().get_thread_infos();
+}
+
+}
--- /dev/null
+/*
+* Copyright 2013 Sveriges Television AB http://casparcg.com/
+*
+* This file is part of CasparCG (www.casparcg.com).
+*
+* CasparCG is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* CasparCG is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with CasparCG. If not, see <http://www.gnu.org/licenses/>.
+*
+* Author: Helge Norberg, helge.norberg@svt.se
+*/
+
+#pragma once
+
+#include <string>
+#include <cstdint>
+#include <vector>
+
+#include "memory.h"
+
+#include <tbb/atomic.h>
+
+#include <boost/thread/thread.hpp>
+
+namespace caspar {
+
+struct thread_info
+{
+ std::string name;
+ std::int64_t native_id;
+
+ thread_info();
+};
+
+thread_info& get_thread_info();
+std::vector<spl::shared_ptr<thread_info>> get_thread_infos();
+
+}
std::map<int, port> ports_;
prec_timer sync_timer_;
boost::circular_buffer<const_frame> frames_;
- executor executor_ = { L"output" };
+ executor executor_ = { L"output " + boost::lexical_cast<std::wstring>(channel_index_) };
public:
impl(spl::shared_ptr<diagnostics::graph> graph, const video_format_desc& format_desc, int channel_index)
: graph_(std::move(graph))
#include <common/lock.h>
#include <common/env.h>
#include <common/prec_timer.h>
-#include <common/os/scheduling.h>
+#include <common/os/threading.h>
#include <common/timer.h>
#include <SFML/Graphics.hpp>
#include <core/video_format.h>
#include <boost/property_tree/ptree.hpp>
+#include <boost/lexical_cast.hpp>
#include <tbb/concurrent_queue.h>
#include <tbb/spin_mutex.h>
namespace caspar { namespace core {
struct mixer::impl : boost::noncopyable
-{
+{
+ int channel_index_;
spl::shared_ptr<diagnostics::graph> graph_;
audio_mixer audio_mixer_;
spl::shared_ptr<image_mixer> image_mixer_;
- executor executor_ { L"mixer" };
+ executor executor_ { L"mixer " + boost::lexical_cast<std::wstring>(channel_index_) };
public:
- impl(spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<image_mixer> image_mixer)
- : graph_(std::move(graph))
+ impl(int channel_index, spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<image_mixer> image_mixer)
+ : channel_index_(channel_index)
+ , graph_(std::move(graph))
, image_mixer_(std::move(image_mixer))
{
graph_->set_color("mix-time", diagnostics::color(1.0f, 0.0f, 0.9f, 0.8f));
}
};
-mixer::mixer(spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<image_mixer> image_mixer)
- : impl_(new impl(std::move(graph), std::move(image_mixer))){}
+mixer::mixer(int channel_index, spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<image_mixer> image_mixer)
+ : impl_(new impl(channel_index, std::move(graph), std::move(image_mixer))){}
void mixer::set_master_volume(float volume) { impl_->set_master_volume(volume); }
float mixer::get_master_volume() { return impl_->get_master_volume(); }
std::future<boost::property_tree::wptree> mixer::info() const{return impl_->info();}
// Constructors
- explicit mixer(spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<image_mixer> image_mixer);
+ explicit mixer(int channel_index, spl::shared_ptr<diagnostics::graph> graph, spl::shared_ptr<image_mixer> image_mixer);
// Methods
namespace caspar { namespace core {
struct stage::impl : public std::enable_shared_from_this<impl>
-{
+{
+ int channel_index_;
spl::shared_ptr<diagnostics::graph> graph_;
- spl::shared_ptr<monitor::subject> monitor_subject_;
- //reactive::basic_subject<std::map<int, draw_frame>> frames_subject_;
- std::map<int, layer> layers_;
+ spl::shared_ptr<monitor::subject> monitor_subject_ = spl::make_shared<monitor::subject>("/stage");
+ std::map<int, layer> layers_;
std::map<int, tweened_transform> tweens_;
interaction_aggregator aggregator_;
// map of layer -> map of tokens (src ref) -> layer_consumer
std::map<int, std::map<void*, spl::shared_ptr<write_frame_consumer>>> layer_consumers_;
- executor executor_;
+ executor executor_ { L"stage " + boost::lexical_cast<std::wstring>(channel_index_) };
public:
- impl(spl::shared_ptr<diagnostics::graph> graph)
- : graph_(std::move(graph))
- , monitor_subject_(spl::make_shared<monitor::subject>("/stage"))
+ impl(int channel_index, spl::shared_ptr<diagnostics::graph> graph)
+ : channel_index_(channel_index)
+ , graph_(std::move(graph))
, aggregator_([=] (double x, double y) { return collission_detect(x, y); })
- , executor_(L"stage")
{
graph_->set_color("produce-time", diagnostics::color(0.0f, 1.0f, 0.0f));
}
}
};
-stage::stage(spl::shared_ptr<diagnostics::graph> graph) : impl_(new impl(std::move(graph))){}
+stage::stage(int channel_index, spl::shared_ptr<diagnostics::graph> graph) : impl_(new impl(channel_index, std::move(graph))){}
std::future<std::wstring> stage::call(int index, const std::vector<std::wstring>& params){return impl_->call(index, params);}
std::future<void> stage::apply_transforms(const std::vector<stage::transform_tuple_t>& transforms){ return impl_->apply_transforms(transforms); }
std::future<void> stage::apply_transform(int index, const std::function<core::frame_transform(core::frame_transform)>& transform, unsigned int mix_duration, const tweener& tween){ return impl_->apply_transform(index, transform, mix_duration, tween); }
// Constructors
- explicit stage(spl::shared_ptr<diagnostics::graph> graph);
+ explicit stage(int channel_index, spl::shared_ptr<diagnostics::graph> graph);
// Methods
, image_mixer_(std::move(image_mixer))
, format_desc_(render_video_mode)
, output_(spl::make_unique<thumbnail_output>(generate_delay_millis))
- , mixer_(graph_, image_mixer_)
+ , mixer_(0, graph_, image_mixer_)
, thumbnail_creator_(thumbnail_creator)
, media_info_repo_(std::move(media_info_repo))
, producer_registry_(std::move(producer_registry))
caspar::core::mixer mixer_;
caspar::core::stage stage_;
- executor executor_ { L"video_channel" };
+ executor executor_ { L"video_channel " + boost::lexical_cast<std::wstring>(index_) };
public:
impl(int index, const core::video_format_desc& format_desc, std::unique_ptr<image_mixer> image_mixer)
: monitor_subject_(spl::make_shared<monitor::subject>(
, format_desc_(format_desc)
, output_(graph_, format_desc, index)
, image_mixer_(std::move(image_mixer))
- , mixer_(graph_, image_mixer_)
- , stage_(graph_)
+ , mixer_(index, graph_, image_mixer_)
+ , stage_(index, graph_)
{
graph_->set_color("tick-time", caspar::diagnostics::color(0.0f, 0.6f, 0.9f));
graph_->set_text(print());
#include <common/os/system_info.h>
#include <common/os/filesystem.h>
#include <common/base64.h>
+#include <common/thread_info.h>
#include <core/producer/cg_proxy.h>
#include <core/producer/frame_producer.h>
return create_info_xml_reply(AMCPCommandQueue::info_all_queues(), L"QUEUES");
}
+void info_threads_describer(core::help_sink& sink, const core::help_repository& repo)
+{
+ sink.short_description(L"Lists all known threads in the server.");
+ sink.syntax(L"INFO THREADS");
+ sink.para()->text(L"Lists all known threads in the server.");
+}
+
+std::wstring info_threads_command(command_context& ctx)
+{
+ std::wstringstream replyString;
+ replyString << L"200 INFO THREADS OK\r\n";
+
+ for (auto& thread : get_thread_infos())
+ {
+ replyString << thread->native_id << L"\t" << u16(thread->name) << L"\r\n";
+ }
+
+ replyString << L"\r\n";
+ return replyString.str();
+}
+
void diag_describer(core::help_sink& sink, const core::help_repository& repo)
{
sink.short_description(L"Open the diagnostics window.");
repo.register_command( L"Query Commands", L"INFO SYSTEM", info_system_describer, info_system_command, 0);
repo.register_command( L"Query Commands", L"INFO SERVER", info_server_describer, info_server_command, 0);
repo.register_command( L"Query Commands", L"INFO QUEUES", info_queues_describer, info_queues_command, 0);
+ repo.register_command( L"Query Commands", L"INFO THREADS", info_threads_describer, info_threads_command, 0);
repo.register_command( L"Query Commands", L"DIAG", diag_describer, diag_command, 0);
repo.register_command( L"Query Commands", L"BYE", bye_describer, bye_command, 0);
repo.register_command( L"Query Commands", L"KILL", kill_describer, kill_command, 0);