🚧
Syscalls: a fronteira entre user-space e kernel
⏱ 14 min de leitura·+70 XP
Toda vez que seu programa abre um arquivo, faz uma requisição de rede ou aloca memória, ele pede ao kernel para fazer isso em seu nome. Syscalls são o único ponto de entrada para o kernel — entender esse mecanismo explica latência, segurança e por que buffering importa.
Ring protection e o modelo de proteção da CPU
# Syscalls comuns que Python faz internamente:
# read() — ler arquivo/socket
# write() — escrever em arquivo/socket/stdout
# open() — abrir arquivo
# close() — fechar file descriptor
# mmap() — mapear memória
# brk()/mmap()— alocar memória heap (malloc usa esses)
# socket() — criar socket de rede
# connect() — conectar a servidor TCP
# accept() — aceitar conexão TCP
# epoll_*() — multiplexação de I/O (usado pelo asyncio)
# clone() — criar processo/thread
# execve() — executar programa
# exit() — terminar processo
# Python não expõe syscalls diretamente (use ctypes/cffi ou a lib os)
import os
# open() Python → sys.call open() → retorna file descriptor (int)
fd = os.open("/etc/hostname", os.O_RDONLY)
dados = os.read(fd, 256)
os.close(fd)
print(dados.decode())
# Verificar syscall number no Linux x86-64:
# /usr/include/asm/unistd_64.h ou ausyscall --list
# read = 0
# write = 1
# open = 2
# close = 3
# mmap = 9
# exit = 60strace: observando syscalls em tempo real
# Usar strace para observar um programa Python:
# strace -f python meu_script.py 2>&1 | head -50
# Output de exemplo (strace de python -c "open('/tmp/x', 'w')"):
# execve("/usr/bin/python3", ["python3", "-c", "open(...)"], envp) = 0
# ... inicialização do interpretador ...
# openat(AT_FDCWD, "/tmp/x", O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0666) = 3
# fstat(3, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
# ioctl(3, TCGETS, 0x...) = -1 ENOTTY (not a tty) ← detecta se é terminal
# close(3) = 0
# Comandos úteis do strace:
# strace -p PID # attach a processo rodando
# strace -c python script.py # sumário de contagem por syscall
# strace -e trace=file python script.py # filtra syscalls relacionadas a arquivo
# strace -e trace=network python script.py # syscalls de rede
# strace -T python script.py # mostra tempo de cada syscall
# Exemplo de output de strace -c:
# % time seconds usecs/call calls errors syscall
# ------ --------- ----------- --------- --------- --------
# 40.12 0.001234 123 10 read
# 25.45 0.000783 78 10 write
# 10.23 0.000314 31 10 mmap
# ...
# perf (sem overhead de strace):
# perf stat python script.py # contadores de hardware (cache misses, etc.)
# perf top # profiling em tempo real de qualquer processoBuffering: reduzindo syscalls
| Modo | Quando flush | Syscalls | Uso |
|---|---|---|---|
| Unbuffered | A cada write() | Muitas | stderr, I/O crítico |
| Line-buffered | A cada \n | Moderadas | stdout em terminal |
| Fully-buffered | Buffer cheio (~8KB) | Poucas | stdout em arquivo/pipe |
| O_DIRECT | A cada write() sem cache kernel | Muitas mas sem double-copy | Bancos de dados |
import os, sys
# Ver e controlar buffering em Python
print(sys.stdout.buffer.raw.name) # '<stdout>'
# stdout em terminal: line-buffered
# stdout em pipe/arquivo: fully-buffered
# Forçar escrita imediata
print("mensagem urgente", flush=True) # flush=True na chamada
sys.stdout.flush() # flush manual
# O_DIRECT: escrever sem cache do kernel (bancos de dados usam isso)
# O banco gerencia seu próprio cache (buffer pool) e não quer dupla cópia
import ctypes
# Syscall vread/write com O_DIRECT bypassa page cache
# Requer alinhamento de 512 bytes no buffer e offset
# Usado por PostgreSQL para wal_sync_method = open_sync
# Medir overhead de syscalls com perf:
# perf stat -e syscalls:sys_enter_read,syscalls:sys_enter_write python script.py✅
Takeaways: cada syscall custa ~100-300ns de overhead de troca de contexto. Minimize syscalls com buffering (padrão em Python). Use
strace -c para identificar quais syscalls dominam o tempo. eBPF/bpftrace são alternativas de produção com overhead mínimo. seccomp limita syscalls disponíveis para containers — base do Docker sandboxing.💡
Próximo: File descriptors e I/O — por que "tudo é arquivo" no Linux e como processos compartilham file descriptors.
🧩
Quiz rápido
3 perguntas · Acerte tudo e ganhe o badge 🎯 Gabarito
Continue lendo