2015-02-09 1 views
1

У меня есть старое приложение на C++, работающее на OS X (10.10/Yosemite).C++ Pipe, слишком много открытых файлов, Errno 25

Когда я отладки приложения, я получаю исключение на этом следующие строки кода:

// create pipe 
    int pipefd[2]; 
    int piperet = pipe(pipefd); 
    if(piperet) 
    { 
     wcsncpy(errbuf, CEmpError::GetErrorText(CEmpError::ERR_SYSTEM, L"Can't create pipe for IPC.", errno).c_str(), errbuflen); 
     CEmpError::LogError(errbuf); 
     return CEmpError::ERR_SYSTEM; //= 115 
    } 

Таким образом, приложение работает и делает эти строки кода несколько раз. Через некоторое время pipette - -1. Код ошибки errno равен 25.

После некоторых исследований это означает «Слишком много открытых файлов». Есть ли способ обхода всех этих открытых файлов? Или можно узнать, какие файлы открыты слишком много?

Когда я набираю в Терминале ulimit -a я получаю:

core file size   (blocks, -c) 0 
data seg size   (kbytes, -d) unlimited 
file size    (blocks, -f) unlimited 
max locked memory  (kbytes, -l) unlimited 
max memory size   (kbytes, -m) unlimited 
open files      (-n) 2560 
pipe size   (512 bytes, -p) 1 
stack size    (kbytes, -s) 8192 
cpu time    (seconds, -t) unlimited 
max user processes    (-u) 709 
virtual memory   (kbytes, -v) unlimited 

Так что я не супер C++ - профессионал, здесь необходимый код линий. Угадайте, что все ненужные трубы или pipefd будут закрыты.

// create pipe 
    int pipefd[2]; 
    int piperet = pipe(pipefd); 
    if(piperet) 
    { 
     wcsncpy(errbuf, CEmpError::GetErrorText(CEmpError::ERR_SYSTEM, L"Can't create pipe for IPC.", errno).c_str(), errbuflen); 
     CEmpError::LogError(errbuf); 
     return CEmpError::ERR_SYSTEM; 
    } 

    CEmpError *pError = 0; 

    // after transfer the execution bit could be reset, so set the rights back 
    chmod(args[0], S_IWUSR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 

    pid_t pid = fork(); 
    if(pid == 0) 
    { // child process 

     close(pipefd[0]); // close reading end 
     int fd = pipefd[1]; 

     // redirect stdout and stderr to pipe 
    dup2(fd, STDOUT_FILENO); 
    dup2(fd, STDERR_FILENO); 

    close(fd); // not needed anymore 

     // execute steup.sh with built argument list 
     execvp(args[0], (char**)args); 

     // if we ever reached this line the exec failed and we need to report error to parent process 
     // once we are in child process we will print the error into stdout of our child process 
     // and parent process will parse and return it to the caller. 
     char buf[128]; 
     sprintf(buf, "setup.sh:ERROR:PI%03d",CEmpError::ERR_EXEC); 

     perror(buf); 

     // keep the process alive until the parent process got the error from the pipe and killed this child process 
     sleep(5); 

     return CEmpError::ERR_EXEC; 
    } 
    else if (pid > 0) 
    { // parent process 
     delete[] args[0]; // release memory allocated to f. 
     delete[] args[3]; // release memory allocated to log f. 
     delete[] args[5]; // release memory allocated to pn 
     close(pipefd[1]); 

     pParser = new CPackageInstallerParser(); 

     FILE* fp = fdopen(pipefd[0], "r"); 
     /*int res = */setvbuf(fp, NULL, _IOLBF, 0); 

     try 
     { 
      pParser->ParseOutput(fp, statusCallback, statusContext, logFileName); 
     } 
     catch (CEmpError* pErr) 
     { 
      if (pErr->ErrorCode == CEmpError::ERR_EXEC) 
       kill(pid, SIGABRT); // the error is parsed kill the child process 
      pError = pErr; 
     } 
     catch (...) 
     { 
      // some exception from statusCallback 
      fclose(fp); 
      delete pParser; 
      pParser = NULL; 
      throw; 
     } 

     fclose(fp); 

     int stat; 
     // wait for the installation process to end. 
     waitpid(pid, &stat, 0); 

     if (WIFEXITED(stat) && (stat % 256 == 0) && pError == NULL) 
     { 
      // exited normally with code 0 (success) 
      // printf("Installed succesfully!\n"); 

      // register succesful operation result 
      try 
      { 
       RegisterResult(operation); 
      } 
      catch (CEmpError* pErr) 
      { 
       pError = pErr; 
      } 
     } 
     else 
     { 
      if (pError == NULL) // no error was caught by parser 
       pError = new CEmpError(CEmpError::ERR_UNKNOWN); 
      //dumpError(stat); 
     } 
    } 
    else 
     pError = new CEmpError(CEmpError::ERR_FORK); 


    //clean up and exit 
    if (pParser != NULL) 
     delete pParser; 
    pParser = NULL; 

    int exitcode = 0; 
    if (pError != NULL) 
    { 
     exitcode = pError->ErrorCode; 
     wcsncpy(errbuf, pError->GetErrorText().c_str(), errbuflen); 
     pError->Log(); 
     delete pError; 
    } 
    return exitcode; 

ответ

2

Вы должны закрыть FDS трубы с close, когда вам больше не нужны.

+0

uao. смешанные ошибки C с исключениями C++! выглядит беспорядок – GameDeveloper

2

Вам разрешено иметь 2560 открытых файлов для каждого процесса, поэтому вам больше не нужно закрывать другие файлы и/или каналы.

Это всегда хороший совет по выпуску ресурсов, когда вы закончите с ними.

+0

Я думал, что «Soft-Limit» - 2560, а «Hard-Limit» неограничен »ulimit -Sn' и' ulimit -Hn' мне это сказал. –

+0

Является ли это мягким или жестким пределом, кажется, что у вас много открытых файлов. Поэтому в любом случае будьте осторожны с ресурсами, которые вы потребляете. –