2015-07-03 3 views
2

Я инициализация демона в C в Debian:C Программа демон использует 100% использование центрального процессора

/** 
* Initializes the daemon so that mcu.serial would listen in the background 
*/ 
void init_daemon() 
{ 
    pid_t process_id = 0; 
    pid_t sid = 0; 

    // Create child process 
    process_id = fork(); 

    // Indication of fork() failure 
    if (process_id < 0) { 
     printf("Fork failed!\n"); 
     logger("Fork failed", LOG_LEVEL_ERROR); 
     exit(1); 
    } 

    // PARENT PROCESS. Need to kill it. 
    if (process_id > 0) { 
     printf("process_id of child process %i\n", process_id); 
     exit(0); 
    } 

    //unmask the file mode 
    umask(0); 
    //set new session 
    sid = setsid(); 

    if(sid < 0) { 
     printf("could not set new session"); 
     logger("could not set new session", LOG_LEVEL_ERROR); 
     exit(1); 
    } 

    // Close stdin. stdout and stderr 
    close(STDIN_FILENO); 
    close(STDOUT_FILENO); 
    close(STDERR_FILENO); 
} 

Главный демон работает в фоновом режиме и контролирует последовательный порт для связи с микроконтроллером - он читает периферийных устройств (например, нажатия кнопок) и передает ему информацию. Основной функциональный цикл:

int main(int argc, char *argv[]) 
{ 
    // We need the port to listen to commands writing 
    if (argc < 2) { 
     fprintf(stderr,"ERROR, no port provided\n"); 
     logger("ERROR, no port provided", LOG_LEVEL_ERROR); 
     exit(1); 
    } 
    int portno = atoi(argv[1]); 

    // Initialize serial port 
    init_serial(); 

    // Initialize server for listening to socket 
    init_server(portno); 

    // Initialize daemon and run the process in the background 
    init_daemon(); 

    // Timeout for reading socket 
    fd_set setSerial, setSocket; 
    struct timeval timeout; 
    timeout.tv_sec = 0; 
    timeout.tv_usec = 10000; 

    char bufferWrite[BUFFER_WRITE_SIZE]; 
    char bufferRead[BUFFER_READ_SIZE]; 
    int n; 
    int sleep; 
    int newsockfd; 
    while (1) 
    { 
     // Reset parameters 
     bzero(bufferWrite, BUFFER_WRITE_SIZE); 
     bzero(bufferRead, BUFFER_WRITE_SIZE); 
     FD_ZERO(&setSerial); 
     FD_SET(fserial, &setSerial); 
     FD_ZERO(&setSocket); 
     FD_SET(sockfd, &setSocket); 

     // Start listening to socket for commands 
     listen(sockfd,5); 
     clilen = sizeof(cli_addr); 
     // Wait for command but timeout 
     n = select(sockfd + 1, &setSocket, NULL, NULL, &timeout); 
     if (n == -1) { 
      // Error. Handled below 
     } 

     // This is for READING button 
     else if (n == 0) { 
      // This timeout is okay 
      // This allows us to read the button press as well 

      // Now read the response, but timeout if nothing returned 
      n = select(fserial + 1, &setSerial, NULL, NULL, &timeout); 
      if (n == -1) { 
       // Error. Handled below 
      } else if (n == 0) { 
       // timeout 
       // This is an okay tiemout; i.e. nothing has happened 
      } else { 
       n = read(fserial, bufferRead, sizeof bufferRead); 
       if (n > 0) { 
        logger(bufferRead, LOG_LEVEL_INFO); 
        if (strcmp(stripNewLine(bufferRead), "ev b2") == 0) { 
         //logger("Shutting down now", LOG_LEVEL_INFO); 
         system("shutdown -h now"); 
        } 
       } else { 
        logger("Could not read button press", LOG_LEVEL_WARN); 
       } 
      } 
     } 

     // This is for WRITING COMMANDS 
     else { 
      // Now read the command 
      newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); 

      if (newsockfd < 0 || n < 0) logger("Could not accept socket port", LOG_LEVEL_ERROR); 

      // Now read the command 
      n = read(newsockfd, bufferWrite, BUFFER_WRITE_SIZE); 
      if (n < 0) { 
       logger("Could not read command from socket port", LOG_LEVEL_ERROR); 
      } else { 
       //logger(bufferWrite, LOG_LEVEL_INFO); 
      } 

      // Write the command to the serial 
      write(fserial, bufferWrite, strlen(bufferWrite)); 
      sleep = 200 * strlen(bufferWrite) - timeout.tv_usec; // Sleep 200uS/byte 
      if (sleep > 0) usleep(sleep); 

      // Now read the response, but timeout if nothing returned 
      n = select(fserial + 1, &setSerial, NULL, NULL, &timeout); 
      if (n == -1) { 
       // Error. Handled below 
      } else if (n == 0) { 
       // timeout 
       sprintf(bufferRead, "err\r\n"); 
       logger("Did not receive response from MCU", LOG_LEVEL_WARN); 
      } else { 
       n = read(fserial, bufferRead, sizeof bufferRead); 
      } 
      // Error reading from the socket 
      if (n < 0) { 
       logger("Could not read response from serial port", LOG_LEVEL_ERROR); 
      } else { 
       //logger(bufferRead, LOG_LEVEL_INFO); 
      } 

      // Send MCU response to client 
      n = write(newsockfd, bufferRead, strlen(bufferRead)); 
      if (n < 0) logger("Could not write confirmation to socket port", LOG_LEVEL_ERROR); 
     } 

     close(newsockfd); 
    } 

    close(sockfd); 
    return 0; 
} 

Но использование ЦП всегда на 100%. Почему это? Что я могу сделать?

EDIT

Я закомментировал Целые во время цикла и сделал основную функцию так просто, как:

int main(int argc, char *argv[]) 
{ 
    init_daemon(); 
    while(1) { 
     // All commented out 
    } 
    return 0; 
} 

И я все еще получаю 100% использование центрального процессора

+2

Id «Предположим, что проблема в цикле' while (1) {...} 'где-то. –

+0

Ну, я включил весь цикл while. Это довольно долго, поэтому я не знаю, как его упростить, чтобы кто-то мог его прочитать и понять, не вдаваясь в подробности! – Kousha

+0

Запустить профилировщик и посмотреть, где потрачено время? – chrylis

ответ

5

Вам нужно чтобы установить timeout в нужное значение на каждой итерации, структура становится модифицированной в Linux, поэтому я думаю, что ваш цикл не приостанавливается, за исключением первого раза, то есть select() блокирует только ве в первый раз.

Попробуйте напечатать tv_sec и tv_usec после select() и посмотреть, это изменен, чтобы отразить, сколько времени осталось до select() вернулся.

Переместить эту часть

timeout.tv_sec = 0; 
timeout.tv_usec = 10000; 

внутри цикла перед select() вызова и он должен работать, как вы ожидаете, вы можете переместить много delcarations внутри цикла тоже, что бы сделать ваш код проще maintan, вы могли бы, например, перенести содержимое цикла в функцию в будущем, и это может помочь.

Это из linux manual page select(2)

На Linux, select() изменяет тайм-аут, чтобы отражать количество времени, которое не было; большинство других реализаций этого не делают. (POSIX.1-2001 допускает либо поведение.) Это вызывает проблемы, когда код Linux, который считывает таймаут, переносится в другие операционные системы и когда код переносится на Linux , который повторно использует struct timeval для нескольких select() s в цикле без повторной инициализации. Подумайте о том, что таймаут не определен после возврата select().

Я думаю, что смелая часть в qoute является важной.

+0

действительно ... в Linux? – jdl

+0

Спасибо! Это сделало трюк – Kousha

+0

, поэтому проблема не является большим тайм-аутом, но 0 тайм-аут, так как значение тайм-аута падает на каждую итерацию и в конечном итоге на 0, как и в «while (1)» – jdl

Смежные вопросы