Portál AbcLinuxu, 4. prosince 2025 10:58
Na EXIT_SUCCESS ti skončí rodičovskej process, forknutej child ti IMHO pokračuje dál.
No normalne ten kod dejte za to TODO. Jestli vam jde o to ujistit se, ze na pozadi opravdu bezi vas kod, tak si treba zapiste nejakou hlasku do logu.
Jinak muzete vyuzit bud uz zminene volani daemon(), nebo program daemon, ktery libovolny jiny program spusti na pozadi (dokaze ho taky znovu spustit, pokud chcipne, etc.).
Nedělal jsem tedy zápis do logu, ale v tom svém kódu zapisuji data do souboru, ale nic se neděje.
Flushnul jste je po tom zápisu? Jinak se v souboru typicky nic neobjeví, dokud jich nezapíšete 4 KB nebo soubor nezavřete.
A jseš si vědomej toho, že ten kód mění aktuální pracovní adresář na "/", takže pokuď zadáváš do open/fopen relativní cestu, snaží se ten soubor vytvořit v "/"? Mimochodem, kontroluješ návratové kódy toho zápisu?
Takže všchny návratový hodnoty jsou ok, přesto se soubor nevytvoří, ano? To je nějaký divný, nemyslíš?! Bohužel nám začínají docházet věštecký koule, takže co kdyby si sem konečně nahrál ten tvůj kód. Uštří to čas tobě i nám...
while(1)
{
fw1 = fopen("/home/pokus.txt", "a");
if (fw1 == NULL)
{
fprintf(stderr, "%s %i:", __FILE__, __LINE__);
perror(NULL);
abort();
return errno;
}
else
{
for (int i=1; i<10; i++)
{
fprintf(fw1, "%i ", i);
}
fprintf(fw1, "\n", "");
}
fclose(fw1);
sleep(10);
}
Ok. Pokusím se ti popsat co dělá ten kód co kopíruješ odsuď v případě, že deamonize = 1 (respektive deamonize != NULL && deamonize != 0).
Zdá se, že spoléháte na to, že alokovaný struct obsahuje samé nuly. Což obecně nemusí být pravda, a nemusí to být ani vhodné. Každopádně pokud začínáte s prázdnou "struct termios", tak se doporučuje napřed použít cfmakeraw(). V některých distrech (verzích glibc?) se nám dokonce osvědčilo ještě před cfmakeraw() strčit bzero(&moje_termios,sizeof(moje_termios)); tj. zaručeně ten struct dospod vynulovat.
Takže vlastně ani není jisté, jestli máte zapnutý nebo vypnutý "canonical processing" (taková terminálová chytristika, která může žrát některé znaky).
Taky tam nikde nevidím flow control (CRTSCTS), což bych doporučoval. Používáte na fyzickém portu flow control nebo ne? Aby tam náhodou nepřetékalo FIFO...
S Vaším problémem to nesouvisí, ale taky není špatný nápad staré nastavení termios pro daný sériový port napřed zazálohovat, a při ukončení programu zase vrátit zpátky.
Tady je útržek zdrojáku z nějakého mého projektu, kde používám sériový port pro "surová data":
struct termios mine;
line->saved = (struct termios*) malloc(sizeof(struct termios));
result = tcgetattr(fd,line->saved); // get the current serial line settings
cfmakeraw(&mine); // a combo (see man cfmakeraw)
cfsetispeed(&mine,mogrify_baud(line->baud)); // input speed
cfsetospeed(&mine,mogrify_baud(line->baud)); // output speed
mine.c_cflag |= (CLOCAL | CREAD); // not an owner of the tty; receiver on
mine.c_cflag &= ~CSIZE; // set data bits
mine.c_cflag |= mogrify_bits(line->bits); // actual number of data bits
// parity:
if (mogrify_par(line->parity) == ~PARENB)
mine.c_cflag &= ~PARENB; // no parity
else
mine.c_cflag |= mogrify_par(line->parity); // some kinda parity is enabled
// stop bits:
if (mogrify_stopb(line->stopbits) == ~CSTOPB)
mine.c_cflag &= ~CSTOPB; // only one stop bit, not two
else
mine.c_cflag |= CSTOPB; // two stop bits
// flow control
if (line->flow > 0)
mine.c_cflag |= CRTSCTS; // hardware flow control
else
mine.c_cflag &= ~CRTSCTS; // no flow control
//mine.c_cc[VMIN] = 10; // ? minimum volume (bytes)
//mine.c_cc[VTIME] = 0; // ? timeout (if no data received)
result = tcsetattr(fd,TCSANOW,&mine); // apply the settings
V tom kódu jsou odkazy na další moje pomocné funkce mogrify_*() které přepracovávají moji "lidskou" konfiguraci na nelidské opšny termios
Celé to najdete tady, jmenuje se to "serial probes". Není to žádný výkvět programátorské čistoty a elegance... uvidíte sám.
S čím se to po sériové lince bavíte? Je to fakt RS232, není to 422/485? (Na half-duplexních sběrnicích nefunguje flow control.) Pokud je to RS232, které signály máte v kabelu zapojeny?
Aha, vy ten device otvíráte read-only... tzn. nic neposíláte... čili tam možná flow control fyzicky není. A možná je kabel zadrátovaný tak, aby to fungovalo s i bez flow control (jenom klema v konektoru) - takže když UART přestane stíhat, tak "zdroj dat" stejně posílá dál. Ale že by počítač nestíhal 9600bps? Podivné...
Koukám do Vašeho zdrojáku, že ten sériový port je nějaký USB dongle. Co je to konkrétně za kousek? Jaký to má čip? Nebyl by výstřižek z dmesg, kde je ten dongle detekován? Nebo výpis lsusb... Různé USB dongly by se mohly lišit hloubkou FIFO bufferu v UARTu.
Hloupej nápad: nejede Vám několik zapomenutých instancí toho démona paralelně?
[362032.304531] ftdi_sio ttyUSB0: FTDI USB Serial Device converter now disconnected from ttyUSB0 [362032.304587] ftdi_sio 3-2:1.0: device disconnected [362044.324454] usb 1-7: USB disconnect, address 5 [362100.104117] usb 5-1: new full speed USB device using uhci_hcd and address 2 [362100.302338] ftdi_sio 5-1:1.0: FTDI USB Serial Device converter detected [362100.302504] usb 5-1: Detected FT232BM [362100.302513] usb 5-1: Number of endpoints 2 [362100.302521] usb 5-1: Endpoint 1 MaxPacketSize 64 [362100.302529] usb 5-1: Endpoint 2 MaxPacketSize 64 [362100.302536] usb 5-1: Setting MaxPacketSize 64 [362100.303369] usb 5-1: FTDI USB Serial Device converter now attached to ttyUSB0 [362182.533603] r8169 0000:01:00.0: eth1: link down [362189.364953] r8169 0000:01:00.0: eth1: link up [362396.131222] ttyUSB0: 6 input overrun(s) [363407.962925] ttyUSB0: 7 input overrun(s) [363719.626233] show_signal_msg: 12 callbacks suppressedTeď se dívám, že v dmesg je i toto:
[363719.626245] monkotel-daemon[23575]: segfault at 1 ip 00799b33 sp bfdfc0ec error 4 in libc-2.12.1.so[759000+157000] [364095.010147] ttyUSB0: 7 input overrun(s) [364557.204599] ttyUSB0: 7 input overrun(s)To je ten můj daemon. Můžete mi někdo naznačit co mi to říka? Jinak běžím na ITX desce s Atomem N270, čipová sada je tam nějaká ta intel945, nevím teď přesně.
Žeby malý buffer v hardwaru?
http://www.ftdichip.com/Products/ICs/FT232BM.htm
Žeby 384B bylo málo? Na 9.6kbps? To je nějaký blábol... Jinak FTDI je asi nejlepší značka USB/232 převodníků. Ty hlášky "input overrun(s)" jsou patrně z generického TTY subsystému, ovladač USB Serial podle mého jenom předá TTY subsystému informaci, že FT232 zahlásil overrun.
http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=blob;f=drivers/usb/serial/ftdi_sio.c (a hledejte "overrun".)
Spíš mi to přijde, jako že démon se kdesi zamyslí/zacyklí/usne navždy, přitom má otevřené zařízení ttyUSB0. No a poté co se naplní kernelový buffer, pak i hardwarový buffer FT232, tak si FT232 začně stěžovat přes USB, že mu přetéká buffer - a ta hláška se dostane skrz TTY subsystém až do dmesg.
Segfault v libc? To by ten démon měl především umřít
A jinak by to klidně mohl být důsledek neinicializovaných termios (no pod haubnou to neznám). Chtělo by to zjistit, kde to přesně chcíplo (pokud se to stává při každém spuštění) = pustit démona přes GDB a v momentě kdy chcípne, tak si udělat bt (=backtrace). Vypadne Vám z toho call stack funkcí, odkud se ten program dostal do místa, kde zhavaroval. Předpoklad je, že ten program máte zkompilovaný s g++ opšnou "-g". Něco málo by ukázal i strace (ukáže jenom syscally, nevidí jednotlivé "řádky programu" ani knihovní funkce).
Žeby ten démon po pádu zůstal z nějakého důvodu ve stavu "zombie"? To je divné, na detached proces snad není potřeba explicitně čekat, jako u vláken. Přemejšlím, jestli se do toho stavu nemůže dostat vlastním přičiněním, třeba vymaskováním nějakého signálu potřebného k nanebevzetí... ale moc tomu nevěřím.
Koukejte, jestli ty hlášky v logu přibývají, jestli to není jenom historický pozůstatek nějakých předchozích pokusů. Pokud přibývají, tak to ten démon dělá pořád a máte na co se zaměřit.
Nechodivým IRQčkem USB OHCI to nebude - to by kromě dat nechodily ani ty varovné URBy že overrun.
Mrkněte se, kde voláte jaké syscally ve smyčce, možná předpokládáte, že ten syscall bude blokovat, a on se přitom okamžitě vrátí s nějakou chybovou hláškou... atp. Nejjednodušší způsob, jak to nalézt, je možná tento: přidejte si na pár míst v programu jednoduché hlášky typu syslog(LOG_INFO,"checkpoint 123") a pomocí "tail -f /var/log/messages" sledujte, kudy program běží. Viz též "man syslog". Já obvykle dávám tyhle hlášky na začátek zajímavých funkcí a cyklů, případně před a za podezřelé syscally - dám jich tam třeba 4-5 ks a pak postupně zužuji oblast, kde se program zasekne. Používat takovouhle instrumentaci moc nejde v časově kritických cyklech, ale to nebude Váš problém...
V kernelu je jeden vtipný způsob, jak se dostat do podobné situace "mimo hlavní stezku programu", a to je špatně napsaná obsluha level-triggered interruptu (takže se obsluha volá pořád dokola) - ale v user space k tomu těžko hledám analogii, například špatnou prací se signály si program spíš odříznete od signálů, než zacyklíte... V user space je taky humorné naběhnout si na nekonečnou autorekurzi
ale to poznáte, program během pár vteřin sežere celou volnou RAMku. Aby se Vám interně zacyklil syscall nebo knihovní funkce libc, to se stává opravdu vyjímečně.
A ještě mě napadá, pokud vidíte příliš velkou spotřebu CPU za celý proces, není ten proces náhodou "rozvlákněný"? Třeba já když píšu vícevláknového démona, tak si ve funkci main() spustím pár vláken-pracantů, a prvotní rodičovské vlákno se třeba jenom zasekne ve věčném sleep() uvnitř "while (true)" smyčky a víceméně čeká na signál k ukončení... Nemohlo se stát, že Vám bůhvíproč cyklí nějaké další vlákno, vedle Vašeho "pracanta", který se chová normálně? Ještě mě napadá, že "top -H" by mohl ukázat jednotlivá vlákna...
nohup.
Program se napise jako normalni aplikace a pak se spousti pomoci nohup /bin/program > /dev/null 2>&1 &napr. z /etc/rc.local Vysledek je stejny a clovek usetri dle meho nazoru zbytecnou praci. Tot jenom pro uplnost tematu. Jeste lepsi je mozna pouzit
start-stop-deamon
start-stop-daemon --pidfile /var/run/mujprogram.pid --start --background --exec /bin/sleep -- 10... kde jako bonus ziskame pidfile, a je tak otazka scriptu na 5 radku implementovat standardni
/etc/init.d/mujprogram start, /etc/init.d/mujprogram restart ... atd ...
nohup nemá se spuštěním na pozadí nic společného, to má na starosti ten ampersand na konci. Stejně tak se nestará ani o další opatření, která jsou u démonů běžná. Příkaz nohup je jen wrapper, který zajistí, že váš program nebude ukončen signálem HUP.
Tiskni
Sdílej:
ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.