/* * mp3plot - Bitrate analysis tool * * Copyright (C) 2007 Toni Corvera * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ // $Id: spinner.cc 703 2007-05-17 20:07:32Z $ #include "spinner.h" #include #include #include #include #include extern int errno; namespace net_outlyer { const char * spinner::SYMS = "|/-\\"; void spinner::start() { if (-1 == pipe(pfd)) { perror("pipe"); return; // FIXME: throw something } pid = fork(); if (-1 == pid) { perror("fork"); return; // FIXME: throw something } // Parent process if (0 != pid) { close(pfd[0]); // Close the unneeded (read) channel // Parent process, we're done here, return to the caller // the parent tasks are in step and stop return; } // Child process assert( 0 == pid ); // see nice(2): // A call to nice that returns -1 might be successful (e.g. -11 + 10). // errno must be checked explicitly to be sure errno=0; if (-1 == nice(+10)) { if (errno != 0) { // FIXME: Do something more useful exit(1); assert( 0 ); return; } } close(pfd[1]); // Close the write end, unneeded // Wait for the parent process to send something through the pipe // (for each byte received a spin will be made). When the cannel // is closed (EOF) process will stop and this thread end char devnull, idx=0; const char LEN=strlen(SYMS); while (read(pfd[0], &devnull, 1) > 0) { std::cerr << "\r[" << SYMS[idx] << "]"; idx = ( idx + 1 ) % LEN; } close(pfd[0]); exit(0); // quite important... } // This is called from the parent thread, it writes a byte on the shared pipe void spinner::step() { write(pfd[1], ".", 1); } // This is called from the parent thread, it sends the EOF (by closing the // pipe) and hence the child should end. void spinner::stop() { if (pid > 0 && !stopped) { // Parent close(pfd[1]); // If already closed, it will fail and errno set to EBADF stopped = true; // We can do the child stopping in two fashions: // * wait() for it to end, this is nicer but kind of kills the benefits // of using separate processes as we'll be blocked by console I/O // anyway (although we'll be blocked *after* the file is processed) // * kill() it. This prevents the child from finishing the spinner // nicely so we need to finish it here (send \r to the err channel) // DISCARDED: wait(NULL); // wait for the buffer to flush kill(pid, SIGTERM); std::cerr << std::flush << "\r" << std::flush; } } spinner::~spinner() { stop(); } } // namespace net_outlyer /* vim:set ts=4 et ai: */