Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-devel / 2013-08

TCustomApplication

25 messages · 7 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Michael Schnell

Hi Experts.

Since ages I am searching for an "easy" method to do "normal (i.e. "event driven") Pascal programming using Lazarus as an IDE and targeting headless embedded devices (with no GUI hardware and/or GUI software infrastructure).

I understand that the fpc RTL already provides TCustomApplication (while Lazarus creates descendants from same to do "Lazarus Applications" - of several kinds, definable by Lazarus "WidgetTypes" - in the LCL).

Now, unfortunately, there is no predefined "WidgetType" that out of the box allows for event driven programming using "normal" stuff like TTimer, TThread.Synchronize, TThread,Queue, and
Application.QueuAsnycCall without forcing a GUI binding (while all this seems to be possible with mseide).

In fact some years ago I tried to create an LCL Widget Type like that, using the "Lazarus Way", but failed due to the complexity of the LCL.

I understand that (without using the LCL at all), in the RTL, it is possible to do e.g. an "Application" that provides at least one timer (see testtimer.pp) or things like a "DaemonApplication (see daemonapp.pp). At least the "DaemonApplication" seems to auto-adapt to Linux or Windows while being compiled.

But here it seems, the application programmer needs to dedicatedly tailor his code for a very special kind of application himself.

Is there (or would it be viable to have in an LCL-independent package) a more general "TCustomApplication" descendant such as "TApplication" or similar, that (auto-adapting to Linux and Windows when being compiled) provides TTimer, TThread.Synchronize, TThread,Queue, and Application.QueuAsnycCall, while allowing for decent "event driven" programming ? Here a decent (OS-dependent) mechanism needs to be implemented to notify the main thread of timer and Thread generated events so that it is able to try to fetch the next event from the queue as soon as possible after (and only when) at least one has been generated.

I would happily try to do something like that myself, but at least for the rest of this year I will not find the time :( . But as this thought comes in my mind, I now try to collect information on this issue.

Thanks,
-Michael

Reply by email

Michael Van Canneyt
to Michael Schnell
Michael Schnell wrote 6 lines
Hi Experts. I would happily try to do something like that myself, but at least for the rest of this year I will not find the time :( . But as this thought comes in my mind, I now try to collect information on this issue.

I am having a déjà vu :-)

I have told you many years ago on these very mailing lists that what you need to do is create a TCustomApplication" descendant which implements a simple event loop. This can be done based on libevent, fpasync, lnet, glib event loop, dbus or some other custom-made mechanism.

If memory serves me well, MSEGUI contains such an event loop descendent using a custom made mechanism.

There is nothing magical about such an application. Basically, it watches one or more file descriptors (object handles in windows-speak) for changes, using a timeout, and triggers some event handler when something happens. It calls checksynchronize from time to time. That's it.

It should not take more than an hour to implement.

Michael.

Reply by email

Michael Schnell
to Michael Van Canneyt: I am having a déjà vu :-) I have told you many years ago on these very mailing lists…
Michael Van Canneyt wrote
I am having a déjà vu :-)

Yep.
But at that time I (maybe completely erroneously) decided to do this as an LCL Widget Type as I had extensions in mind that would fit just there (such as stuff based on "ExtPascal" or "mse-ifi").

If memory serves me well, MSEGUI contains such an event loop descendent using a custom made mechanism.

Of course. In fact I understand that any LCL Widget Type does this, too.

Show quoted text 9 lines
There is nothing magical about such an application. Basically, it watches one or more file descriptors (object handles in windows-speak) for changes, using a timeout, and triggers some event handler when something happens. It calls checksynchronize from time to time. That's it. It should not take more than an hour to implement.

In fact I do know this. If I would have a current practical project to do, I of course would do this right away, but (as always) I am doing just researching and groundwork for future projects.

So - if I would start doing anything on that behalf - I would do something with as wide reach as possible: providing (at least) all of TTimer, TThread.Synchronize, TThread,Queue, and
Application.QueuAsnycCall, as well for Linux and for Windows in a "ready to use" way (including documentation).

In fact the cause why this becomes more prominent for me right now is that since some time "TThread.Queue" is provided in the rtl (in fact on my request and happily implemented by very knowledgeable supporters like yourself) and thus I feel that in a similar way TTimer and Application.QueuAsnycCall would be doable.

-Michael (known as the weird mind)

Reply by email

Michael Van Canneyt
to Michael Schnell: Yep. But at that time I (maybe completely erroneously) decided to do this as an LCL…
Michael Schnell wrote 27 lines
On 08/19/2013 11:28 AM, Michael Van Canneyt wrote: > > I am having a déjà vu :-) Yep. But at that time I (maybe completely erroneously) decided to do this as an LCL Widget Type as I had extensions in mind that would fit just there (such as stuff based on "ExtPascal" or "mse-ifi"). > If memory serves me well, MSEGUI contains such an event loop descendent > using a custom made mechanism. Of course. In fact I understand that any LCL Widget Type does this, too. > > There is nothing magical about such an application. Basically, it watches > one or more > file descriptors (object handles in windows-speak) for changes, using a > timeout, > and triggers some event handler when something happens. It calls > checksynchronize from time to time. That's it. > > It should not take more than an hour to implement. In fact I do know this. If I would have a current practical project to do, I of course would do this right away, but (as always) I am doing just researching and groundwork for future projects. So - if I would start doing anything on that behalf - I would do something with as wide reach as possible: providing (at least) all of TTimer,

You may need to do ttimer if you need that.

TThread.Synchronize, TThread,Queue, and Application.QueuAsnycCall, as well for Linux and for Windows in a "ready to use" way (including documentation).

YOU DO NOT NEED TO DO THIS.

Just implement the loop and let it call CheckSynchronize at regular intervals. All the rest will be done for you.

Michael.

Reply by email

Michael Schnell
to Michael Van Canneyt
Michael Van Canneyt wrote 7 lines
YOU DO NOT NEED TO DO THIS. Just implement the loop and let it call CheckSynchronize at regular intervals. All the rest will be done for you.

Did you ever do embedded software ?

The result of the event in the main queue is not having something displayed to a human, but may be a command to the attached "machine", which might be really fast.

Thus regular polling is an absolute no-go here.

Doing the polling "slow" results in huge latency regarding the events.

Doing the polling "fast" results in a huge processor overhead and thus in a huge overhead regarding anything else that the CPU is supposed to do.

-Michael

Reply by email

Martin Schreiber
to Michael Schnell: _MANY_ thanks for the support, making me feel that I am not completely insane. -Michael
Michael Schnell wrote 7 lines
On 08/19/2013 11:51 AM, Martin Schreiber wrote: > Maybe some additional minutes for the implementation of an efficient > and precise timer queue. ;-) _MANY_ thanks for the support, making me feel that I am not completely insane.

BTW, why don't you simply use MSEgui which provides all this out of the box instead to constantly annoy FPC and Lazarus people? ;-)

Martin

Reply by email

Henry Vermaak
to Michael Schnell: Did you ever do embedded software ? The result of the event in the main queue is not…
Michael Schnell wrote 21 lines
On 08/19/2013 01:47 PM, Michael Van Canneyt wrote: > >YOU DO NOT NEED TO DO THIS. > >Just implement the loop and let it call CheckSynchronize at >regular intervals. >All the rest will be done for you. > Did you ever do embedded software ? The result of the event in the main queue is not having something displayed to a human, but may be a command to the attached "machine", which might be really fast. Thus regular polling is an absolute no-go here. Doing the polling "slow" results in huge latency regarding the events. Doing the polling "fast" results in a huge processor overhead and thus in a huge overhead regarding anything else that the CPU is supposed to do.

You don't need to poll. Just make sure that you assign and implement WakeMainThread (classes.pp). When Synchronize() is called, it will check if WakeMainThread is assigned and call it. This will wake up your main loop and you can then call CheckSynchronize().

How you implement WakeMainThread will depend on your event loop mechanism. A simple way to do this is with the self-pipe trick.

Henry

Reply by email

Sven Barth
to Michael Van Canneyt: You may need to do ttimer if you need that. YOU DO NOT NEED TO DO THIS. Just implement…
Michael Van Canneyt wrote 10 lines
> TThread.Synchronize, TThread,Queue, and Application.QueuAsnycCall, as > well for Linux and for Windows in a "ready to use" way (including > documentation). YOU DO NOT NEED TO DO THIS. Just implement the loop and let it call CheckSynchronize at regular intervals. All the rest will be done for you.

(Except QueueAsyncCall which is only implemented in the LCL's TApplication and is not triggered by CheckSynchronize)

Regards,
Sven

Reply by email

Michael Schnell
to Martin Schreiber: BTW, why don't you simply use MSEgui which provides all this out of the box instead to…
Martin Schreiber wrote
BTW, why don't you simply use MSEgui which provides all this out of the box instead to constantly annoy FPC and Lazarus people? ;-)

(We already did discuss this years ago ;-) . I do hope that just asking a question each year is not too annoying....)

I am (supposedly) not going to a "use" anything to do any real applications at all, but I am doing some groundwork to help my colleagues to port some of their Delphi stuff to Linux.

I am quite sure that I will not be able to have the 30 years Delphi users switch to mse, but some hope remains to talk them into using Lazarus.

Right now, there is news by Embarcadero that the next version of Delphi will support doing native ARM application on Android devices. Thus Linux _is_ going to be supported somehow.

But here they would need to switch to FireMonkey. This might be close to impossible, again, while the LCL is much closer to the legacy Delphi VCL.

-Michael

Reply by email

Michael Schnell
to Henry Vermaak: You don't need to poll. Just make sure that you assign and implement WakeMainThread…
Henry Vermaak wrote
How you implement WakeMainThread will depend on your event loop mechanism. A simple way to do this is with the self-pipe trick.

Of course this is exactly what I have in mind.

(But as said, I am doing nothing but groundwork research and don't have an actual application in mind. Thus if I am going to do anything it would need to be only be useful it it is widely usable for a greater class of applications.

-Michael

Reply by email

Michael Van Canneyt
to Michael Schnell: Did you ever do embedded software ? The result of the event in the main queue is not…
Michael Schnell wrote 9 lines
On 08/19/2013 01:47 PM, Michael Van Canneyt wrote: > > YOU DO NOT NEED TO DO THIS. > > Just implement the loop and let it call CheckSynchronize at regular > intervals. > All the rest will be done for you. > Did you ever do embedded software ?

Yes.

Show quoted text 11 lines
The result of the event in the main queue is not having something displayed to a human, but may be a command to the attached "machine", which might be really fast. Thus regular polling is an absolute no-go here. Doing the polling "slow" results in huge latency regarding the events. Doing the polling "fast" results in a huge processor overhead and thus in a huge overhead regarding anything else that the CPU is supposed to do.

So what ? That's a detail of the event loop.

It has nothing to do with the mechanism of threads.

Michael.

Reply by email

Michael Van Canneyt
to Michael Schnell
Michael Schnell wrote 9 lines
On 08/19/2013 02:35 PM, Michael Van Canneyt wrote: > > So what ? That's a detail of the event loop. My comment was not regarding " event loop" but regarding " regular intervals". If you implement an event loop that does not do turns on regular intervals but only when it gets tickled by the event generating Thread or timer. I am of course fine.

I will not implement anything, you will :)

Michael.

Reply by email

Hans-Peter Diettrich
to Michael Schnell: Yep. But at that time I (maybe completely erroneously) decided to do this as an LCL…
Show quoted text 5 lines
So - if I would start doing anything on that behalf - I would do something with as wide reach as possible: providing (at least) all of TTimer, TThread.Synchronize, TThread,Queue, and Application.QueuAsnycCall, as well for Linux and for Windows in a "ready to use" way (including documentation).

Now that you mention it, a new TApplication type would be a good choice. From D7 help:

TServiceApplication encapsulates a Windows NT service application. Unit: SvcMgr

DoDi

Reply by email

Michael Schnell
to Henry Vermaak: You don't need to poll. Just make sure that you assign and implement WakeMainThread…
Henry Vermaak wrote
A simple way to do this is with the self-pipe trick.

I suppose in Windows we would use a message. In Linux I would prefer a semaphore or - supposedly best if really usable here - pthread.mutex as same uses FUTEX whenever the underlying arch allows for and thus the overhead is as small as possible, because there is no OS call necessary when scheduling an event and when an event is already scheduled at the time the previous is done.

-Michael

Reply by email

Henry Vermaak
to Michael Schnell
Michael Schnell wrote 8 lines
On 08/19/2013 02:27 PM, Henry Vermaak wrote: >A simple way to do this is with the self-pipe trick. I suppose in Windows we would use a message. In Linux I would prefer a semaphore or - supposedly best if really usable here - pthread.mutex as same uses FUTEX whenever the underlying arch allows for and thus the overhead is as small as possible, because there is no OS call necessary when scheduling an event and when an event is already scheduled at the time the previous is done.

That makes no sense. How do you suppose that a mutex in linux will wake up an event loop?

Henry

Reply by email

Michael Schnell
to Henry Vermaak
Henry Vermaak wrote
How do you suppose that a mutex in linux will wake up an event loop?

The mutex gets taken before the loop is started. Now the loop blocks when taking it. It is freed whenever an event is scheduled.

Whether or not a mutex blocks when the same thread tries to take it that already owns it and whether a thread that does not "own" it can free it, is an implementation detail that here of course needs to be taken into account. (I once did a Mutex implementation that did block on re-take, but AFAIK there are different implementations.)

AFAIR the FUTEX system call (that is not a MUTEX itself, but only helps to implement one in user space) allows for doing this. But I don't know what in detail pthread.mutex does in detail.

(Anyway, I'll be doing a research on those details when I in fact should do an "Application" implementation that needs it.)

-Michael

Reply by email

Henry Vermaak
to Michael Schnell
Michael Schnell wrote 5 lines
On 08/19/2013 04:31 PM, Henry Vermaak wrote: >How do you suppose that a mutex in linux will wake up an event loop? The mutex gets taken before the loop is started. Now the loop blocks when taking it. It is freed whenever an event is scheduled.

So, only one event can ever wake up your even loop? I usually use select() or epoll(). I'm looking forward to seeing your implementation, though. However, judging by how long you've been talking about this, I think I'll be retired by then.

Henry

Reply by email

Paul Breneman
to Michael Schnell: Right you are :-) . I sincerely hope I once will find the time to do this, now that we…
Michael Schnell wrote 7 lines
On 08/19/2013 02:48 PM, Michael Van Canneyt wrote: > > I will not implement anything, you will :) Right you are :-) . I sincerely hope I once will find the time to do this, now that we TThread.Queue which proves that it in fact is possible.

I'm enjoying this thread (one of my favorites every year :) ) and I am glad to learn that things are progressing!

Reply by email