Scheduling no Linux, Starvation no X11 e o Paradigma Wayland

No meu ambiente (Ubuntu 25.04, KDE Plasma 6, X11), percebi que o painel e os widgets travavam durante compilações pesadas ou processos do FFmpeg, enquanto as janelas propriamente continuavam fluindo normalmente

Por exemplo, o navegador, o terminal, trabalhavam sem oscilação, porém os componentes de painel e widgets paravam de responder consideravelmente.

1. Fundamentos do Scheduling no Unix

O Unix clássico (System V, BSD) implementava um agendador simples e cooperativo, baseado em prioridades fixas. Cada processo tinha um valor de nice (de −20 a +19), e o sistema concedia um quantum de tempo (geralmente 10 ms) a cada processo conforme sua prioridade.

Quando todos tinham prioridade igual, o sistema fazia round-robin.

Não havia preempção dentro do kernel nem consciência de I/O ou GPU — apenas tempo de CPU.

Podemos dizer que o scheduling do Unix original e o das primeiras versões do Windows (3.x, 95, 98, ME) compartilham a mesma filosofia cooperativa, porém com mecanismos diferentes de controle e preempção.

O scheduling do Unix clássico

No Unix original (anos 70–80, System V, BSD 4.x):

  • O sistema era multitarefa cooperativa com prioridades, depois evoluindo para preemptiva com “time slices”.
  • Cada processo possuía uma prioridade estática e dinâmica, ajustada com base no uso de CPU e I/O.
  • O kernel fazia um round-robin dentro de cada faixa de prioridade.
  • O processo rodava até: esgotar seu quantum de tempo, bloquear em I/O, ou voluntariamente ceder CPU (via sleep() ou wait()).

Ou seja: o sistema confiava que os processos “se comportariam”, devolvendo o controle ao kernel quando terminassem sua parte.

Windows 3.x: multitarefa cooperativa pura

O Windows 3.1 e 3.11 rodavam sobre o MS-DOS, que era single-tasking. O Windows criou um ambiente multitarefa cooperativo — mas só entre aplicações Windows. Programas DOS ainda rodavam de forma exclusiva.

  • Cada aplicativo tinha o controle total da CPU até chamar GetMessage() ou funções do GDI/User.
  • O sistema de janelas dependia de cada app para “renderizar e devolver o tempo”.
  • Se um app travasse ou entrasse em loop, todo o sistema congelava.
  • Não havia preempção de kernel nem prioridades reais.

Isso é análogo ao Unix cooperativo inicial: o agendador confiava que cada processo cederia o CPU voluntariamente.

Esse modelo em UNIX primordial funcionava bem em ambientes de terminal, mas não se adaptava ao multitarefa moderna, com threads, aceleração gráfica e composição de janelas.

Windows 95 / 98 / ME: híbrido cooperativo + preemptivo

Com o Windows 95, a Microsoft introduziu um kernel 32 bits híbrido:

  • Aplicações 32-bit (Win32) eram preemptivamente agendadas.
  • Aplicações 16-bit (legado do Windows 3.x) continuavam cooperativas.
  • O sistema inteiro ainda rodava em um único espaço de endereçamento compartilhado (sem proteção de memória total).
  • O agendador usava quantum curtos (~20 ms) e prioridades fixas para threads.

Resultado: se um aplicativo 16-bit não cedia o controle, ele podia travar as janelas 32-bit também — assim como um processo mal-comportado no Unix cooperativo podia travar o terminal todo.

o scheduling do Unix original é análogo ao das versões iniciais do Windows, especialmente Windows 3.x, e parcialmente ao modelo híbrido de Windows 95/98/ME.

Todos partilhavam a mesma limitação fundamental:

O sistema dependia da boa vontade dos processos em “ceder o tempo”.

Somente com o advento do Unix preemptivo moderno e do Windows NT é que os dois mundos convergiram para o paradigma que usamos hoje — onde o kernel decide, não o processo.


2. Evolução: Linux CFS (Completely Fair Scheduler)

O CFS, introduzido no kernel 2.6.23, é preemptivo e orientado a justiça. Ele organiza as threads em uma árvore RB-tree por CPU, garantindo tempo proporcional ao peso de cada processo.

  • nice = 0 → tempo normal
  • nice = 10 → ~40 % do tempo de CPU
  • nice = −10 → ~250 % mais prioridade

Há também políticas real-time (SCHED_FIFO, SCHED_RR) usadas por áudio, KWin e interrupções, e o SCHED_DEADLINE para latências garantidas.

O CFS, porém, enxerga apenas CPU. Ele não entende esperas em GPU, poll() de drivers ou bloqueios de renderização. Eis o pulo do gato, ou melhor, o gato não pula de lá pra cá.


3. O Starvation que observei no X11 (Plasma 6 + Intel Iris Xe)

Investigando, descobri que o plasmashell usa QtQuick + OpenGL (GLX), e a Intel Iris Xe trabalha com o driver Mesa iris_dri.so, que processa comandos GL em thread pool no userspace.

O que acontecia:

  1. Ao iniciar um make -j8 ou um FFmpeg pesado, todas as CPUs iam a 100 %.
  2. O kernel CFS distribuía CPU igualmente (todos os processos com nice = 0).
  3. O plasmashell ficava aguardando o loop QtQuick renderizar via GLX.
  4. As threads GLX disputavam as mesmas filas que as de FFmpeg.
  5. Chamadas como poll() e drmWaitVBlank() ficavam sem fatia de CPU.
  6. O painel travava, mas o compositor (kwin_x11) seguia normal, pois roda com prioridade RT.

Em resumo: as threads de renderização do painel sofriam starvation de CPU e GPU, enquanto o compositor seguia ativo.


4. Por que o Wayland resolve isso

No Wayland, cada app possui seu próprio EGL surface e canal de comunicação direta com o compositor (via DMA-BUF). Não existe servidor X central nem contexto GLX compartilhado.

Com isso, mesmo que o FFmpeg consuma todos os cores, o compositor Wayland mantém prioridade RT e cada processo continua fluindo de forma independente. O painel não depende mais de GLX nem do X Server — e simplesmente não trava.


5. Relação com o Unix tradicional

O Unix original tratava o display como um recurso monolítico (um servidor X único). O Linux herdou esse modelo, mas o Wayland rompe essa herança e distribui a responsabilidade: entrada, composição e exibição são processos distintos, comunicando-se de forma assíncrona. É como se a garatuja agora fosse um restaurante, onde temos o garçom, a cozinha e os clientes famintos. 🙂

É, na prática, o retorno ao princípio “faça uma coisa e faça bem”, agora aplicado à pilha gráfica.


6. Scheduling no Plasma 6 (na prática)

Componente | Política / Prioridade | Efeito

————————-|—————————|——————————————–

kwin_x11 / kwin_wayland | SCHED_RR (tempo real) | CPU para compor frames

plasmashell | SCHED_OTHER (nice = 0) | Sujeito a starvation no X11

ffmpeg / gcc / make | SCHED_OTHER (nice = 0) | Competem com o painel

PipeWire / PulseAudio | SCHED_RR (tempo real) | Latência garantida

No X11, o plasmashell compartilha contexto GL com outros processos. No Wayland, cada um tem seu contexto e frame loop próprio — isolamento real.


7. Prós e contras da migração para o Wayland

Aspecto | X11 (GLX) | Wayland (EGL / GBM)

—————————–|————————————|———————————————

Modelo de processos | Centralizado (X Server único) | Descentralizado (cada app é um surface)

Gerenciamento de CPU/GPU | Contexto GLX compartilhado | Contextos isolados por app

Starvation sob carga | Frequente | Virtualmente inexistente

V-Sync / tearing | Depende do driver | Sincronizado por design

Compatibilidade | Total (legado) | XWayland (leve overhead)

Ferramentas de automação | xdotool, xrandr, xinput | ydotool, wlr-randr, libinput debug

Segurança | Apps podem acessar janelas alheias| Isolamento completo

Eficiência energética (Intel)| Menor | Maior

Suporte futuro | Manutenção | Desenvolvimento ativo


8. Visualizando o comportamento

No X11:

FFmpeg → CPU 100 %
↓
GLX context lock (iris_dri.so)
↓
poll() bloqueia
↓
plasmashell 0 % CPU
↓
painel travado, kwin ok 

No Wayland:

FFmpeg → CPU 100 %
↓
Wayland compositor (RT)
↓
plasmashell em surface EGL
↓
painel redesenha normalmente 

9. Conclusão

Essa análise me mostrou de forma clara como o comportamento do scheduler e a arquitetura gráfica se entrelaçam:

  • Unix: agendador cooperativo e display monolítico.
  • Linux + X11: preempção justa, mas servidor global suscetível a starvation.
  • Wayland: isolamento completo e sincronização moderna via EGL.

Migrar para o Wayland me trouxe estabilidade, fluidez e isolamento real das cargas de CPU/GPU, especialmente com hardware Intel Iris Xe. O agendador continua o mesmo — mas agora, a pilha gráfica trabalha com ele, e não contra ele.


<3 “O Wayland não é apenas o sucessor do X — é a reconciliação entre o kernel e o compositor.”

Diversas vezes critiquei o wayland não pelo seu design mas por lack of features. Eu acho que os benefícios em estabilidade e até mesmo segurança, compensam muito o deficit em algumas áreas que sequer são tão utilizadas; acho digno que se mova em frente quanto a implementar essas lacunas do que manter-se arraigado num conceito antiquado, num paradigma que funciona bem mas apresenta vulnerabilidades e falhas devido a sua concepção estrutural.

Basta que as distros mantenham ambos a la carte e c1est la vie. Keep moving forward.

Minha mais simples matemática: Conhecimento dividido é poder multiplicado!