Посмотрел на это немного больше и подготовил следующий пример, представленный без гарантии, но который работает для меня для тысяч вызовов AuthorizationExecuteWithPrivileges без проблем:
void DoOtherStuff(AuthorizationRef auth, char* path);
void DoStuff(char* path)
{
AuthorizationItem foo;
foo.name = kAuthorizationRightExecute;
foo.value = NULL;
foo.valueLength = 0;
foo.flags = 0;
AuthorizationRights rights;
rights.count = 1;
rights.items = &foo;
AuthorizationRef authorizationRef;
OSStatus err = errAuthorizationSuccess;
if (errAuthorizationSuccess != (err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef)))
{
NSLog(@"Error on AuthorizationCreate: %lu", (long)err);
return;
}
for (NSUInteger i = 0; i < 5000; i++)
{
NSLog(@"Doing run: %lu", (long)i+1);
DoOtherStuff(authorizationRef, "/tmp/foo");
}
if (errAuthorizationSuccess != (err = AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults)))
{
NSLog(@"Error on AuthorizationFree: %lu", (long)err);
return;
}
}
void DoOtherStuff(AuthorizationRef authorizationRef, char* path)
{
OSStatus err = errAuthorizationSuccess;
FILE *pipe = NULL;
@try
{
char *args[] = {"644", path, NULL};
if (errAuthorizationSuccess != (err = AuthorizationExecuteWithPrivileges(authorizationRef,
"/bin/chmod", kAuthorizationFlagDefaults, args, &pipe)))
{
NSLog(@"Error on AuthorizationExecuteWithPrivileges: %lu", (long)err);
return;
}
int stat;
wait(&stat);
NSLog(@"Success! Child Process Died!");
}
@finally
{
if (pipe)
fclose(pipe);
}
}
То, что сказал Крис Сутер, умерло. Когда вы вызываете AuthorizationExecuteWithPrivileges, происходит то, что он выполняет fork () ваш процесс, а затем exec () запрашиваемый процесс (в данном случае chmod) из дочернего процесса. Дочерний процесс не будет запущен, пока кто-то не вызовет wait (), но это сложно, потому что мы не получаем PID дочернего процесса из AuthorizationExecuteWithPrivileges (он был бы возвращен fork ()). По его словам, если вы уверены, что нет других потоков, порождающих процессы одновременно (т. Е. Ваш поток является единственным, создающим дочерние процессы), то вы можете просто вызвать не ожидающую PID версию wait (), как Я делаю в этом примере.
Если вы не вызываете wait (), то происходит то, что вы накапливаете эти дочерние процессы-зомби, которые все ждут, когда их соберут. В конце концов ОС говорит «больше нет».
Я чувствую себя немного плохо, публикуя это, поскольку это просто повторение того, что сказал Крис Сутер; Я проголосовал за его ответ.
Для полноты, вот переработанная версия этого примера, которая достигает цели, игнорируя SIGCHLD вместо вызова wait. Он также предоставляется без гарантии, но у меня работает.
void DoOtherStuff(AuthorizationRef auth, char* path);
void DoStuff(char* path)
{
AuthorizationItem foo;
foo.name = kAuthorizationRightExecute;
foo.value = NULL;
foo.valueLength = 0;
foo.flags = 0;
AuthorizationRights rights;
rights.count = 1;
rights.items = &foo;
AuthorizationRef authorizationRef;
OSStatus err = errAuthorizationSuccess;
struct sigaction oldAction;
struct sigaction newAction;
newAction.__sigaction_u.__sa_handler = SIG_IGN;
newAction.sa_mask = 0;
newAction.sa_flags = 0;
if(0 != sigaction(SIGCHLD, &newAction, &oldAction))
{
NSLog(@"Couldn't ignore SIGCHLD");
return;
}
@try
{
if (errAuthorizationSuccess != (err = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, kAuthorizationFlagDefaults, &authorizationRef)))
{
NSLog(@"Error on AuthorizationCreate: %lu", (long)err);
return;
}
for (NSUInteger i = 0; i < 1000; i++)
{
NSLog(@"Doing run: %lu", (long)i+1);
DoOtherStuff(authorizationRef, "/tmp/foo");
}
if (errAuthorizationSuccess != (err = AuthorizationFree(authorizationRef, kAuthorizationFlagDefaults)))
{
NSLog(@"Error on AuthorizationFree: %lu", (long)err);
return;
}
}
@finally
{
const struct sigaction cOldAction = oldAction;
if(0 != sigaction(SIGCHLD, &cOldAction, NULL))
{
NSLog(@"Couldn't restore the handler for SIGCHLD");
return;
}
}
}
void DoOtherStuff(AuthorizationRef authorizationRef, char* path)
{
OSStatus err = errAuthorizationSuccess;
FILE *pipe = NULL;
@try
{
char *args[] = {"644", path, NULL};
if (errAuthorizationSuccess != (err = AuthorizationExecuteWithPrivileges(authorizationRef,
"/bin/chmod", kAuthorizationFlagDefaults, args, &pipe)))
{
NSLog(@"Error on AuthorizationExecuteWithPrivileges: %lu", (long)err);
return;
}
NSLog(@"Success!");
}
@finally
{
if (pipe)
fclose(pipe);
}
}