Subject: Re: bug#57196: 28.1.90; An idea to allow background (low-priority) threads

From: Eli Zaretskii <[email-masked]>
Date: Sun, 14 Aug 2022 16:37:12 +0300

> From: Ihor Radchenko <[email-masked]>
> Cc: [email-masked]
> Date: Sun, 14 Aug 2022 15:57:37 +0800
> 
> Eli Zaretskii <[email-masked]> writes:
> 
> > Our "scheduler", such as it is, is in thread.c:really_call_select.  It
> > basically releases the global lock and lets the first thread waiting
> > on the lock to acquire the lock.  If someone wants to implement a
> > smarter lock-grabbing logic with some kind of "nice" capability, AFAIU
> > that's the place to look and modify.
> 
> Do I understand correctly that thread.c:really_call_select simply relies
> on pthread itself to select the next thread?

What do you mean by "pthread itself"?  AFAIU, threads are scheduled
by the OS, not by pthreads.  So which thread will be the next to grab
the lock is up to the OS, the way we programmed it.

> Then, a simple pthread_setschedparam inside
> systhread.c:sys_thread_create may do the job given that we pass an extra
> optional parameter to make-thread.

You could try that and see if that helps, although I wouldn't know how
you'd select the policy in this case.

> 1. There is main thread and the magit/agenda thread
> 2. Magit/agenda thread uses a lot of CPU while the main thread is not (I
>    was typing/navigating the buffer)
> 3. Every keypress in the main thread caused thread switch to the
>    CPU-hungry magit/agenda thread
> 4. Frequent switches caused high typing latency because every single key
>    stroke in the main thread had to wait until the magit/agenda yields.

The only way of improving the UX in this case is for the other thread
to yield more frequently.

> I do not suggest to stop the running thread externally.
> 
> Instead, we may accumulate the thread execution time. Let's call this
> "thread 1".
> 
> Then, every time the _other_ running thread yields (stops itself) and
> "thread 1" is about to be called, we do the following:
> 1. If "thread 1" execution time is less than "duration" thread
>    property, run the thread.
> 2. If "thread 1" execution time is more than "duration", skip running
>    the thread remembering the time now (pause time).
> 3. If "thread 1" execution time is more than "duration" and "pause time"
>    was more than "break time" thread property ago, set execution time to
>    0 and allow the thread to be running.

You can do this in your thread function: when it gets to run, check
whether it "earned" its time slot, and if not, yield immediately
without calling the workhorse code.