Fixes high CPU load

This commit is contained in:
Markus Gans 2020-08-15 23:42:29 +02:00
parent c2894b6591
commit 5574104dd9
12 changed files with 156 additions and 122 deletions

View File

@ -1,3 +1,8 @@
2020-08-15 Markus Gans <guru.mail@muenster.de>
* The call of the function setNonBlockingRead() resulted in
a high CPU load in idle mode.
Thanks to Pavel Stehule for reporting this problem.
2020-08-11 Markus Gans <guru.mail@muenster.de>
* New callback backend was implemented. Callback functions with any
number of arguments are now possible.

View File

@ -20,9 +20,11 @@
* <http://www.gnu.org/licenses/>. *
***********************************************************************/
#include <chrono>
#include <fstream>
#include <memory>
#include <string>
#include <thread>
#include "final/fapplication.h"
#include "final/fevent.h"
@ -61,7 +63,8 @@ FMouseControl* FApplication::mouse {nullptr}; // mouse control
int FApplication::loop_level {0}; // event loop level
int FApplication::quit_code {EXIT_SUCCESS};
bool FApplication::quit_now {false};
uInt64 FApplication::next_event_wait{50000}; // preset to 50 ms
struct timeval FApplication::time_last_event{};
//----------------------------------------------------------------------
// class FApplication
@ -330,6 +333,7 @@ void FApplication::closeConfirmationDialog (FWidget* w, FCloseEvent* ev)
void FApplication::processExternalUserEvent()
{
// This method can be overloaded and replaced by own code
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
@ -337,6 +341,10 @@ void FApplication::processExternalUserEvent()
//----------------------------------------------------------------------
void FApplication::init()
{
// Initialize the last event time
time_last_event.tv_sec = 0;
time_last_event.tv_usec = 0;
// Initialize keyboard
keyboard = FTerm::getFKeyboard();
@ -1207,10 +1215,10 @@ void FApplication::processResizeEvent() const
//----------------------------------------------------------------------
void FApplication::processCloseWidget()
{
setTerminalUpdates (FVTerm::stop_terminal_updates);
if ( ! getWidgetCloseList() || getWidgetCloseList()->empty() )
return;
if ( getWidgetCloseList() && ! getWidgetCloseList()->empty() )
{
setTerminalUpdates (FVTerm::stop_terminal_updates);
auto iter = getWidgetCloseList()->begin();
while ( iter != getWidgetCloseList()->end() && *iter )
@ -1220,8 +1228,6 @@ void FApplication::processCloseWidget()
}
getWidgetCloseList()->clear();
}
setTerminalUpdates (FVTerm::start_terminal_updates);
}
@ -1243,12 +1249,18 @@ bool FApplication::processNextEvent()
{
uInt num_events{0};
if ( isNextEventTimeout() )
{
FObject::getCurrentTime (&time_last_event);
processKeyboardEvent();
processMouseEvent();
processResizeEvent();
processTerminalUpdate();
processCloseWidget();
processLogger();
updateTerminal();
}
processExternalUserEvent();
sendQueuedEvents();
@ -1318,4 +1330,10 @@ bool FApplication::isEventProcessable ( const FObject* receiver
return true;
}
//----------------------------------------------------------------------
bool FApplication::isNextEventTimeout()
{
return FObject::isTimeout (&time_last_event, next_event_wait);
}
} // namespace finalcut

View File

@ -44,7 +44,9 @@ namespace finalcut
// static class attributes
uInt64 FKeyboard::read_blocking_time{100000}; // preset to 100 ms
uInt64 FKeyboard::key_timeout{100000}; // preset to 100 ms
uInt64 FKeyboard::interval_timeout{75000}; // preset to 75 ms
struct timeval FKeyboard::time_keypressed{};
struct timeval FKeyboard::time_last_request{};
#if defined(__linux__)
FTermLinux* FKeyboard::linux{nullptr};
@ -62,6 +64,8 @@ FKeyboard::FKeyboard()
// Initialize keyboard values
time_keypressed.tv_sec = 0;
time_keypressed.tv_usec = 0;
time_last_request.tv_sec = 0;
time_last_request.tv_usec = 0;
// Get the stdin file status flags
stdin_status_flags = fcntl(FTermios::getStdIn(), F_GETFL);
@ -117,6 +121,9 @@ bool& FKeyboard::unprocessedInput()
//----------------------------------------------------------------------
bool FKeyboard::isKeyPressed() const
{
if ( ! isIntervalTimeout() )
return false;
fd_set ifds{};
struct timeval tv{};
const int stdin_no = FTermios::getStdIn();
@ -125,6 +132,7 @@ bool FKeyboard::isKeyPressed() const
FD_SET(stdin_no, &ifds);
tv.tv_sec = 0;
tv.tv_usec = suseconds_t(read_blocking_time); // preset to 100 ms
FObject::getCurrentTime (&time_last_request);
const int result = select (stdin_no + 1, &ifds, nullptr, nullptr, &tv);
if ( result > 0 && FD_ISSET(stdin_no, &ifds) )
@ -351,11 +359,17 @@ bool FKeyboard::setNonBlockingInput (bool enable)
}
//----------------------------------------------------------------------
bool FKeyboard::isKeypressTimeout()
inline bool FKeyboard::isKeypressTimeout()
{
return FObject::isTimeout (&time_keypressed, key_timeout);
}
//----------------------------------------------------------------------
inline bool FKeyboard::isIntervalTimeout()
{
return FObject::isTimeout (&time_last_request, interval_timeout);
}
//----------------------------------------------------------------------
FKey FKeyboard::UTF8decode (const char utf8[]) const
{

View File

@ -278,7 +278,7 @@ inline void FMessageBox::deallocation()
//----------------------------------------------------------------------
inline void FMessageBox::initCallbacks()
{
if ( button_digit[0] != 0 )
if ( button[0] && button_digit[0] != 0 )
{
button[0]->addCallback
(
@ -288,7 +288,7 @@ inline void FMessageBox::initCallbacks()
);
}
if ( button_digit[1] != 0 )
if ( button[1] && button_digit[1] != 0 )
{
button[1]->addCallback
(
@ -298,7 +298,7 @@ inline void FMessageBox::initCallbacks()
);
}
if ( button_digit[2] != 0 )
if ( button[2] && button_digit[2] != 0 )
{
button[2]->addCallback
(

View File

@ -429,7 +429,7 @@ void FSpinBox::forceFocus()
}
//----------------------------------------------------------------------
void FSpinBox::cb_inputFieldActivate()
void FSpinBox::cb_inputFieldActivate() const
{
processActivate();
}

View File

@ -380,19 +380,7 @@ const FString& FString::operator () () const
//----------------------------------------------------------------------
std::size_t FString::getUTF8length() const
{
if ( ! string )
return 0;
std::size_t len{0};
const char* s = c_str();
while ( *s )
{
len += std::size_t((*s & 0xc0) != 0x80);
s++;
}
return len;
return length;
}
//----------------------------------------------------------------------

View File

@ -56,11 +56,13 @@ bool FVTerm::force_terminal_update{false};
bool FVTerm::no_terminal_updates{false};
bool FVTerm::cursor_hideable{false};
int FVTerm::skipped_terminal_update{};
uInt64 FVTerm::term_size_check_timeout{500000}; // 500 ms
uInt FVTerm::erase_char_length{};
uInt FVTerm::repeat_char_length{};
uInt FVTerm::clr_bol_length{};
uInt FVTerm::clr_eol_length{};
uInt FVTerm::cursor_address_length{};
struct timeval FVTerm::last_term_size_check{};
std::queue<int>* FVTerm::output_buffer{nullptr};
FPoint* FVTerm::term_pos{nullptr};
FSystem* FVTerm::fsystem{nullptr};
@ -1968,6 +1970,10 @@ void FVTerm::init()
createArea (term_geometry, shadow_size, vdesktop);
vdesktop->visible = true;
active_area = vdesktop;
// Initialize the last terminal size check time
last_term_size_check.tv_sec = 0;
last_term_size_check.tv_usec = 0;
}
//----------------------------------------------------------------------
@ -2899,6 +2905,11 @@ bool FVTerm::isInsideTerminal (const FPoint& pos) const
//----------------------------------------------------------------------
inline bool FVTerm::isTermSizeChanged() const
{
if ( ! isTermSizeCheckTimeout() )
return false;
FObject::getCurrentTime (&last_term_size_check);
const auto& data = FTerm::getFTermData();
if ( ! data )
@ -2915,6 +2926,12 @@ inline bool FVTerm::isTermSizeChanged() const
return false;
}
//----------------------------------------------------------------------
inline bool FVTerm::isTermSizeCheckTimeout()
{
return FObject::isTimeout (&last_term_size_check, term_size_check_timeout);
}
//----------------------------------------------------------------------
inline void FVTerm::markAsPrinted (uInt pos, uInt line)
{

View File

@ -198,6 +198,7 @@ class FApplication : public FWidget
bool processNextEvent();
void performTimerAction (FObject*, FEvent*) override;
static bool isEventProcessable (const FObject*, const FEvent*);
static bool isNextEventTimeout();
// Data members
int app_argc{};
@ -205,6 +206,8 @@ class FApplication : public FWidget
uInt64 key_timeout{100000}; // 100 ms
uInt64 dblclick_interval{500000}; // 500 ms
FEventQueue event_queue{};
static uInt64 next_event_wait;
static timeval time_last_event;
static int quit_code;
static bool quit_now;
static int loop_level;

View File

@ -55,13 +55,20 @@ struct FCallbackData
FCallbackData()
{ }
FCallbackData (const FString& s, FWidget* i, void* m, const FCall& c)
template<typename FuncPtr>
FCallbackData (const FString& s, FWidget* i, FuncPtr m, const FCall& c)
: cb_signal(s)
, cb_instance(i)
, cb_function_ptr(m)
, cb_function(c)
{ }
FCallbackData (const FCallbackData&) = default;
FCallbackData (FCallbackData&&) = default;
FCallbackData& operator = (const FCallbackData&) = default;
FCallbackData& operator = (FCallbackData&&) = default;
// Data members
FString cb_signal{};
FWidget* cb_instance{};
@ -77,6 +84,53 @@ struct FCallbackData
class FCallback
{
public:
// Using-declaration
template<typename T>
using ObjectPointer =
typename std::enable_if< ! std::is_member_function_pointer<T>::value
&& ! std::is_function<typename std::remove_pointer<T>::type>::value
&& ! std::is_function<T>::value
&& std::is_pointer<T>::value
&& std::is_object<T>::value
&& ! std::is_class<T>::value
, std::nullptr_t >;
template<typename T>
using ClassObject =
typename std::enable_if< ! std::is_member_function_pointer<T>::value
&& ! std::is_function<typename std::remove_pointer<T>::type>::value
&& ! std::is_function<T>::value
&& ! std::is_pointer<T>::value
&& std::is_object<T>::value
&& std::is_class<T>::value
, std::nullptr_t >;
template<typename T>
using MemberFunctionPointer =
typename std::enable_if< std::is_member_function_pointer<T>::value
&& ! std::is_function<typename std::remove_pointer<T>::type>::value
&& ! std::is_function<T>::value
&& ! std::is_pointer<T>::value
&& std::is_object<T>::value
&& ! std::is_class<T>::value
, std::nullptr_t >;
template<typename T>
using FunctionPointer =
typename std::enable_if< ! std::is_member_function_pointer<T>::value
&& std::is_function<typename std::remove_pointer<T>::type>::value
&& ! std::is_function<T>::value
&& std::is_pointer<T>::value
&& std::is_object<T>::value
&& ! std::is_class<T>::value
, std::nullptr_t >;
template<typename T>
using FunctionReference =
typename std::enable_if< ! std::is_member_function_pointer<T>::value
&& std::is_function<typename std::remove_pointer<T>::type>::value
&& std::is_function<T>::value
&& ! std::is_pointer<T>::value
&& ! std::is_object<T>::value
&& ! std::is_class<T>::value
, std::nullptr_t >;
// Constructors
FCallback();
@ -103,19 +157,8 @@ class FCallback
// Methods
template<typename Object
, typename Function
, typename std::enable_if< ! std::is_member_function_pointer<Object>::value
&& ! std::is_function<typename std::remove_pointer<Object>::type>::value
&& ! std::is_function<Object>::value
&& std::is_pointer<Object>::value
&& std::is_object<Object>::value
&& ! std::is_class<Object>::value
&& std::is_member_function_pointer<Function>::value
&& ! std::is_function<typename std::remove_pointer<Function>::type>::value
&& ! std::is_function<Function>::value
&& ! std::is_pointer<Function>::value
&& std::is_object<Function>::value
&& ! std::is_class<Function>::value
, std::nullptr_t >::type = nullptr
, typename ObjectPointer<Object>::type = nullptr
, typename MemberFunctionPointer<Function>::type = nullptr
, typename... Args>
void addCallback ( const FString& cb_signal
, Object&& cb_instance
@ -125,29 +168,17 @@ class FCallback
// Add a member function pointer as callback
Object instance = cb_instance;
auto member = reinterpret_cast<void*>(std::addressof(cb_member));
auto fn = std::bind ( std::forward<Function>(cb_member)
, std::forward<Object>(cb_instance)
, std::forward<Args>(args)... );
FCallbackData obj{ cb_signal, instance, member, fn };
FCallbackData obj{ cb_signal, instance, nullptr, fn };
callback_objects.push_back(obj);
}
template<typename Object
, typename Function
, typename std::enable_if< ! std::is_member_function_pointer<Object>::value
&& ! std::is_function<typename std::remove_pointer<Object>::type>::value
&& ! std::is_function<Object>::value
&& std::is_pointer<Object>::value
&& std::is_object<Object>::value
&& ! std::is_class<Object>::value
&& ! std::is_member_function_pointer<Function>::value
&& ! std::is_function<typename std::remove_pointer<Function>::type>::value
&& ! std::is_function<Function>::value
&& ! std::is_pointer<Function>::value
&& std::is_object<Function>::value
&& std::is_class<Function>::value
, std::nullptr_t >::type = nullptr
, typename ObjectPointer<Object>::type = nullptr
, typename ClassObject<Function>::type = nullptr
, typename... Args>
void addCallback ( const FString& cb_signal
, Object&& cb_instance
@ -162,13 +193,7 @@ class FCallback
}
template<typename Function
, typename std::enable_if< ! std::is_member_function_pointer<Function>::value
&& ! std::is_function<typename std::remove_pointer<Function>::type>::value
&& ! std::is_function<Function>::value
&& ! std::is_pointer<Function>::value
&& std::is_object<Function>::value
&& std::is_class<Function>::value
, std::nullptr_t >::type = nullptr
, typename ClassObject<Function>::type = nullptr
, typename... Args>
void addCallback ( const FString& cb_signal
, Function&& cb_function
@ -183,13 +208,7 @@ class FCallback
}
template<typename Function
, typename std::enable_if< ! std::is_member_function_pointer<Function>::value
&& std::is_function<typename std::remove_pointer<Function>::type>::value
&& std::is_function<Function>::value
&& ! std::is_pointer<Function>::value
&& ! std::is_object<Function>::value
&& ! std::is_class<Function>::value
, std::nullptr_t >::type = nullptr
, typename FunctionReference<Function>::type = nullptr
, typename... Args>
void addCallback ( const FString& cb_signal
, Function& cb_function
@ -204,13 +223,7 @@ class FCallback
}
template<typename Function
, typename std::enable_if< ! std::is_member_function_pointer<Function>::value
&& std::is_function<typename std::remove_pointer<Function>::type>::value
&& ! std::is_function<Function>::value
&& std::is_pointer<Function>::value
&& std::is_object<Function>::value
&& ! std::is_class<Function>::value
, std::nullptr_t >::type = nullptr
, typename FunctionPointer<Function>::type = nullptr
, typename... Args>
void addCallback ( const FString& cb_signal
, Function&& cb_function
@ -226,13 +239,7 @@ class FCallback
}
template<typename Function
, typename std::enable_if< ! std::is_member_function_pointer<Function>::value
&& ! std::is_function<typename std::remove_pointer<Function>::type>::value
&& ! std::is_function<Function>::value
&& ! std::is_pointer<Function>::value
&& std::is_object<Function>::value
&& std::is_class<Function>::value
, std::nullptr_t >::type = nullptr
, typename ClassObject<Function>::type = nullptr
, typename... Args>
void addCallback ( const FString& cb_signal
, Function& cb_function
@ -246,13 +253,7 @@ class FCallback
}
template<typename Object
, typename std::enable_if< ! std::is_member_function_pointer<Object>::value
&& ! std::is_function<typename std::remove_pointer<Object>::type>::value
&& ! std::is_function<Object>::value
&& std::is_pointer<Object>::value
&& std::is_object<Object>::value
&& ! std::is_class<Object>::value
, std::nullptr_t >::type = nullptr >
, typename ObjectPointer<Object>::type = nullptr>
void delCallback (Object&& cb_instance)
{
// Deletes entries with the given instance from the callback list
@ -290,13 +291,7 @@ class FCallback
}
template<typename Object
, typename std::enable_if< ! std::is_member_function_pointer<Object>::value
&& ! std::is_function<typename std::remove_pointer<Object>::type>::value
&& ! std::is_function<Object>::value
&& std::is_pointer<Object>::value
&& std::is_object<Object>::value
&& ! std::is_class<Object>::value
, std::nullptr_t >::type = nullptr >
, typename ObjectPointer<Object>::type = nullptr>
void delCallback (const FString& cb_signal, Object&& cb_instance)
{
// Deletes entries with the given signal and instance
@ -318,13 +313,7 @@ class FCallback
}
template<typename FunctionPtr
, typename std::enable_if< ! std::is_member_function_pointer<FunctionPtr>::value
&& std::is_function<typename std::remove_pointer<FunctionPtr>::type>::value
&& ! std::is_function<FunctionPtr>::value
&& std::is_pointer<FunctionPtr>::value
&& std::is_object<FunctionPtr>::value
&& ! std::is_class<FunctionPtr>::value
, std::nullptr_t >::type = nullptr >
, typename FunctionPointer<FunctionPtr>::type = nullptr>
void delCallback (FunctionPtr&& cb_func_ptr)
{
// Deletes entries with the given function pointer
@ -346,13 +335,7 @@ class FCallback
}
template<typename Function
, typename std::enable_if< ! std::is_member_function_pointer<Function>::value
&& std::is_function<typename std::remove_pointer<Function>::type>::value
&& std::is_function<Function>::value
&& ! std::is_pointer<Function>::value
&& ! std::is_object<Function>::value
&& ! std::is_class<Function>::value
, std::nullptr_t >::type = nullptr >
, typename FunctionReference<Function>::type = nullptr>
void delCallback (Function& cb_function)
{
// Deletes entries with the given function from the callback list

View File

@ -148,6 +148,7 @@ class FKeyboard final
// Inquiry
static bool isKeypressTimeout();
static bool isIntervalTimeout();
// Methods
FKey UTF8decode (const char[]) const;
@ -171,8 +172,10 @@ class FKeyboard final
#endif
static timeval time_keypressed;
static timeval time_last_request;
static uInt64 read_blocking_time;
static uInt64 key_timeout;
static uInt64 interval_timeout;
fc::FKeyMap* key_map{nullptr};
FKey key{0};
uChar read_character{};

View File

@ -140,7 +140,7 @@ class FSpinBox : public FWidget
void forceFocus();
// Callback methods
void cb_inputFieldActivate();
void cb_inputFieldActivate() const;
void cb_inputFieldChange (const FLineEdit&);
// Data members

View File

@ -408,6 +408,7 @@ class FVTerm
bool updateTerminalCursor() const;
bool isInsideTerminal (const FPoint&) const;
bool isTermSizeChanged() const;
static bool isTermSizeCheckTimeout();
static void markAsPrinted (uInt, uInt);
static void markAsPrinted (uInt, uInt, uInt);
static void newFontChanges (FChar*&);
@ -437,10 +438,12 @@ class FVTerm
static FChar i_ch; // inherit background character
static FPoint* term_pos; // terminal cursor position
static FKeyboard* keyboard;
static timeval last_term_size_check;
static bool terminal_update_complete;
static bool terminal_update_pending;
static bool force_terminal_update;
static bool no_terminal_updates;
static uInt64 term_size_check_timeout;
static int skipped_terminal_update;
static uInt erase_char_length;
static uInt repeat_char_length;