Eu acho que sei o que está acontecendo. No agente / gpg-agent.c do gnupg, esta função processa mensagens do libgcrypt.
/* This is our callback function for gcrypt progress messages. It is
set once at startup and dispatches progress messages to the
corresponding threads of the agent. */
static void
agent_libgcrypt_progress_cb (void *data, const char *what, int printchar,
int current, int total)
{
struct progress_dispatch_s *dispatch;
npth_t mytid = npth_self ();
(void)data;
for (dispatch = progress_dispatch_list; dispatch; dispatch = dispatch->next)
if (dispatch->ctrl && dispatch->tid == mytid)
break;
if (dispatch && dispatch->cb)
dispatch->cb (dispatch->ctrl, what, printchar, current, total);
/* Libgcrypt < 1.8 does not know about nPth and thus when it reads
* from /dev/random this will block the process. To mitigate this
* problem we take a short nap when Libgcrypt tells us that it needs
* more entropy. This way other threads have chance to run. */
#if GCRYPT_VERSION_NUMBER < 0x010800 /* 1.8.0 */
if (what && !strcmp (what, "need_entropy"))
npth_usleep (100000); /* 100ms */
#endif
}
Essa última parte com npth_usleep foi adicionada entre 2.1.15 e 2.1.17. Como isso é condicionalmente compilado se o libgcrypt for mais antigo que o 1.8.0, a correção direta seria recompilar o gnupg contra o libgcrypt 1.8.0 ou posterior… infelizmente essa versão parece não existir ainda.
O mais estranho é que o comentário sobre a leitura da libgcrypt / dev / random não é verdade. Stracing the agent revela que ele está lendo / dev / urandom e usando o novo getrandom (2) syscall, sem bloquear. No entanto, ele envia muitas mensagens need_entropy, fazendo com que npth_usleep bloqueie. A exclusão dessas linhas resolve o problema.
Devo mencionar que npth parece ser algum tipo de biblioteca multitarefa cooperativa, e npth_usleep provavelmente é o seu caminho para render, então pode ser melhor apenas reduzir significativamente esse atraso, caso a libgcrypt decida bloquear algum dia. (1ms não é perceptível)