void mainloop(const bool &Exit) { unsigned char skipped = 0; for (;!Exit;) { if (skipped < temp.frameskip) { skipped++; temp.vidblock = 1; } else skipped = temp.vidblock = 0; if (!temp.vidblock) flip(); for (unsigned f = rsm.needframes[rsm.frame]; f; f--) { temp.sndblock = !conf.sound.enabled; temp.inputblock = temp.vidblock && conf.sound.enabled; spectrum_frame(); VideoSaver(); // message handling before flip (they paint to rbuf) if (!temp.inputblock) { dispatch(conf.atm.xt_kbd ? ac_main_xt : ac_main); } if (!temp.sndblock) { do_sound(); Vs1001.Play(); } if (rsm.mix_frames > 1) { memcpy(rbuf_s + rsm.rbuf_dst * rb2_offs, rbuf, temp.scx * temp.scy / 4); if (++rsm.rbuf_dst == rsm.mix_frames) rsm.rbuf_dst = 0; } if (!temp.sndblock) { /* if(conf.sound.do_sound == do_sound_none) do_idle(); */ } } if (++rsm.frame == rsm.period) rsm.frame = 0; } correct_exit(); }
int main(int argc, char *argv[]) { pthread_attr_t pthread_attr; int opt, /* Буфер для распознания опций argv через getopt */ opt_t = 0; /* Указан ли ключ '-t' */ int null_fd; int rc; /* return code */ #if CATCH_SIGNAL struct sigaction sa; sigset_t sa_set; #endif #ifdef NDEBUG pid_t pid, sid; /* Отделяемся от родительского процесса */ pid = fork(); /* Если не проходит даже форк - значит дела совсем плохи - * завершаем работу тут же. */ if (pid < 0) { perror("fork()"); exit(EXIT_FAILURE); } /* Если дочерний процесс порождён успешно, то родительский процесс можно завершить. */ if (pid > 0) { exit(EXIT_SUCCESS); } #endif /* Открытие журнала на запись */ openlog(SELF_NAME, LOG_ODELAY|LOG_PERROR|LOG_PID, LOG_DAEMON); #ifdef NDEBUG /* Создание нового SID для дочернего процесса */ sid = setsid(); /* Если получить sid не удалось - пытаемся сделать это ещё SETSID_ATEMPTS_COUNT раз */ TRY_N_TIMES(SETSID_ATEMPTS_COUNT, (sid = setsid()), (sid < 0), "setsid()", LOG_CRIT); /* Если после вышеописанных попыток sid всё равно не получен - завершаем работу. */ if (sid < 0) { syslog(LOG_EMERG, "setsid(): %s.", strerror(errno)); exit(EXIT_FAILURE); } #endif #if CATCH_SIGNAL sigemptyset(&sa_set); sigaddset(&sa_set, SIGHUP); sigprocmask(SIG_BLOCK, &sa_set, 0); sa.sa_mask = sa_set; sa.sa_flags = SA_NOMASK; sa.sa_handler = correct_exit; sigaction(SIGTSTP, &sa, 0); sigaction(SIGINT, &sa, 0); sigaction(SIGTERM, &sa, 0); sigaction(SIGQUIT, &sa, 0); #endif /* Изменяем файловую маску */ umask(0); /* Изменяем текущий рабочий каталог */ if (chdir("/") < 0) { syslog(LOG_WARNING, "chdir(): %s.", strerror(errno)); } /* Закрываем стандартные файловые дескрипторы - * теперь вместо них будет /dev/null */ null_fd = open(DEV_NULL_PATH, O_RDWR | O_NONBLOCK); if(null_fd < 0){ syslog(LOG_EMERG, "open(\""DEV_NULL_PATH"\"): %s.", strerror(errno)); exit(EXIT_FAILURE); } close_and_dup_stdfd(STDIN_FILENO, null_fd); #ifdef NDEBUG close_and_dup_stdfd(STDOUT_FILENO, null_fd); close_and_dup_stdfd(STDERR_FILENO, null_fd); #endif /* Заполним страктуру значениями по-умолчанию */ /* server_pool.be_verbose = 0; */ server_pool.threads_count = DEFAULT_THREADS_COUNT; /* Проверим все переданные аргументы */ while ((opt = getopt(argc, argv, "vt:")) != -1) { switch (opt) { case 'v': /* verbose */ server_pool.be_verbose = 1; break; /*case 'c': cache file path break;*/ case 't': /* thread count */ server_pool.threads_count = atoi(optarg); opt_t = 1; if(server_pool.threads_count < 1){ syslog(LOG_WARNING, "Threads count incorrect." "Use default: " DEFAULT_THREADS_COUNT_S); } break; default: /* '?' */ break; } } if(opt_t == 0 && server_pool.be_verbose){ syslog(LOG_NOTICE, "Threads count not specified. " "Use default: " DEFAULT_THREADS_COUNT_S); } /* Получаем адрес сервера. */ if (optind >= argc) { if(server_pool.be_verbose){ syslog(LOG_NOTICE, "Server addres not specified. " "Use default: '" DEFAULT_SERVER_ADDR "'"); } strncpy(server_pool.server_addr, DEFAULT_SERVER_ADDR, MAX_SERVER_ADDR_SIZE); } else{ strncpy(server_pool.server_addr, argv[optind], MAX_SERVER_ADDR_SIZE); } /* Инициализируем барьер. */ if(pthread_barrier_init(&server_pool.proxy_barr, NULL, server_pool.threads_count + 1) ){ syslog(LOG_ERR, "Error in barrier creating."); server_pool.no_barr = 1; } else{ server_pool.no_barr = 0; } /* Резервируем место под нити */ server_pool.tids = (pthread_t *) malloc(sizeof(pthread_t) * server_pool.threads_count); server_pool.context = zmq_ctx_new(); server_pool.clients = zmq_socket(server_pool.context, ZMQ_ROUTER); server_pool.workers = zmq_socket(server_pool.context, ZMQ_DEALER); zmq_bind(server_pool.clients, server_pool.server_addr); zmq_bind(server_pool.workers, ZMQ_INPROC_ADDR); pthread_attr_init(&pthread_attr); pthread_attr_setdetachstate(&pthread_attr, PTHREAD_CREATE_DETACHED); /* sync pthread init */ if(pthread_create(&server_pool.sync_tid, &pthread_attr, &thread_synchronizer, NULL) != 0){ syslog(LOG_EMERG, "Error in sync thread creating."); correct_exit(); } /* cmd pthread init */ /* client pthreads init */ for(int i = 0; i < server_pool.threads_count; i++){ if(pthread_create(&server_pool.tids[i], &pthread_attr, &thread_operator, (void *) i) != 0){ syslog(LOG_EMERG, "Error in thread creating."); correct_exit(); } } pthread_attr_destroy(&pthread_attr); if(server_pool.be_verbose){ syslog(LOG_INFO, "Initialize complete. Start main cycle."); } /* Перед запуском zmq_proxy необходимо открыть все нужные сокеты. * Ожидаем, когда все клиентские нити сделают это. */ if(!server_pool.no_barr){ rc = pthread_barrier_wait(&server_pool.proxy_barr); if(rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD) syslog(LOG_ERR, "Cannot wait on barrier."); else{ pthread_barrier_destroy(&server_pool.proxy_barr); #ifndef NDEBUG syslog(LOG_DEBUG, "Barrier destroy. Start proxy."); #endif } } zmq_proxy(server_pool.clients, server_pool.workers, NULL); return EXIT_SUCCESS; }