Рассмотрим следующую программу:
#include <sys/mman.h>
#include <stdlib.h>
#include <errno.h>
int
main()
{
errno = 0;
mlockall(MCL_FUTURE);
char *a = malloc(1);
if (!a)
exit(errno);
munlockall();
exit(0);
}
При работе от обычного пользователя получаю:
~ ./a.out
~ echo $?
11
От /usr/include/asm-generic/errno-base.h
:
#define EAGAIN 11 /* Try again */
При запуске от имени пользователя root или при передаче MCL_FUTURE | MCL_CURRENT
он работает успешно. Я предположил, что либо прав недостаточно, либо флаги были неправильными, но ни EPERM, ни EINVAL не были возвращены.
Эта ошибка не указана ни в справочной странице ни функций, ни в спецификации POSIX для mlockall. Размещение printf после mlockall показывает, что именно malloc устанавливает errno.
И что еще более странно, malloc, кажется, не устанавливает EAGAIN (или я ищу не в том месте):
/usr/src/glibc/glibc-2.19/malloc grep -r . -e EAGAIN
Так в чем же дело?
~ uname -r 18:15:04
3.16-2-486
~ gcc --version 18:15:05
gcc (Debian 4.9.2-10) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
~ ldd --version 18:15:11
ldd (Debian GLIBC 2.19-18+deb8u1) 2.19
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Written by Roland McGrath and Ulrich Drepper.
~ 18:15:15
errno
в 0, вызываете две функции, а затем проверяете значениеerrno
. Вы не можете сказать, был ли он установленmlockall
илиmalloc
. Вы упомянули добавление вызоваprintf
, но его нет в опубликованном вами коде. Вы должны установитьerrno
в 0 перед каждым вызовом и проверять его сразу после каждого вызова. - person Keith Thompson   schedule 08.12.2015a.out
? - person Fiddling Bits   schedule 08.12.2015mlockall()
. - person Andrew Henle   schedule 08.12.2015malloc(3)
обычно реализуется с использованиемmmap(2)
для получения памяти от ОС. Аmmap(2)
задокументировано как способное установитьerrno
вEAGAIN
, особенно если заблокировано слишком много памяти. - person Nate Eldredge   schedule 08.12.2015mmap(2)
на самом деле вызывается во многих случаях. Фактически, я пытался запустить программу ОП подstrace(1)
. Что происходит, так это то, чтоmalloc
сначала вызываетsbrk(2)
, что терпит неудачу. Затем он возвращается к нескольким вызовамmmap
, все из которых терпят неудачу сEAGAIN
. И это, по-видимому, объясняет, почему возвращаетсяerrno == EAGAIN
, когдаmalloc(3)
возвращается. - person Nate Eldredge   schedule 09.12.2015mmap
вызывается во многих случаях. Но во многих случаях это не так. Ваше утверждение В наши дни malloc(3) обычно реализуется с использованием mmap(2), похоже, подразумевает, что используется исключительноmmap
. Кроме того, предполагая, что OP работает в Linux и использует glibc для источника, который я связал, возвращениеEAGAIN
в случае сбоя, как мне кажется, нарушает стандарт POSIX, а также противоречит его собственной справочной странице. - person Andrew Henle   schedule 09.12.2015ENOMEM
— это единственное значениеerrno
, указанное в описании POSIX дляmalloc(3)
. Но здесь мы видим Реализации... могут генерировать дополнительные ошибки, если явно запрещены для конкретной функции. Поэтому я не думаю, что это нарушение POSIX. - person Nate Eldredge   schedule 09.12.2015