abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    dnes 04:44 | Nová verze

    Po roce vývoje od vydání verze 1.24.0 byla vydána nová stabilní verze 1.26.0 webového serveru a reverzní proxy nginx (Wikipedie). Nová verze přináší řadu novinek. Podrobný přehled v souboru CHANGES-1.26.

    Ladislav Hagara | Komentářů: 0
    dnes 04:33 | Nová verze

    Byla vydána nová verze 6.2 živé linuxové distribuce Tails (The Amnesic Incognito Live System), jež klade důraz na ochranu soukromí uživatelů a anonymitu. Přehled změn v příslušném seznamu. Tor Browser byl povýšen na verzi 13.0.14.

    Ladislav Hagara | Komentářů: 0
    dnes 04:22 | Nová verze

    Byla vydána nová verze 30.0.0 frameworku pro vývoj multiplatformních desktopových aplikací pomocí JavaScriptu, HTML a CSS Electron (Wikipedie, GitHub). Chromium bylo aktualizováno na verzi 124.0.6367.49, V8 na verzi 12.4 a Node.js na verzi 20.11.1. Electron byl původně vyvíjen pro editor Atom pod názvem Atom Shell. Dnes je na Electronu postavena celá řada dalších aplikací.

    Ladislav Hagara | Komentářů: 0
    dnes 04:11 | Nová verze

    Byla vydána nová verze 9.0.0 otevřeného emulátoru procesorů a virtualizačního nástroje QEMU (Wikipedie). Přispělo 220 vývojářů. Provedeno bylo více než 2 700 commitů. Přehled úprav a nových vlastností v seznamu změn.

    Ladislav Hagara | Komentářů: 0
    včera 23:22 | IT novinky

    Evropský parlament dnes přijal směrnici týkající se tzv. práva spotřebitele na opravu. Poslanci ji podpořili 584 hlasy (3 bylo proti a 14 se zdrželo hlasování). Směrnice ujasňuje povinnosti výrobců opravovat zboží a motivovat spotřebitele k tomu, aby si výrobky nechávali opravit a prodloužili tak jejich životnost.

    Ladislav Hagara | Komentářů: 2
    včera 16:11 | Nová verze

    Bylo oznámeno (cs) vydání Fedora Linuxu 40. Přehled novinek ve Fedora Workstation 40 a Fedora KDE 40 na stránkách Fedora Magazinu. Současně byl oznámen notebook Slimbook Fedora 2.

    Ladislav Hagara | Komentářů: 8
    včera 13:44 | Upozornění

    ČTK (Česká tisková kancelář) upozorňuje (X), že na jejím zpravodajském webu České noviny byly dnes dopoledne neznámým útočníkem umístěny dva smyšlené texty, které nepocházejí z její produkce. Jde o text s titulkem „BIS zabránila pokusu o atentát na nově zvoleného slovenského prezidenta Petra Pelligriniho“ a o údajné mimořádné prohlášení ministra Lipavského k témuž. Tyto dezinformace byly útočníky zveřejněny i s příslušnými notifikacemi v mobilní aplikaci Českých novin. ČTK ve svém zpravodajském servisu žádnou informaci v tomto znění nevydala.

    Ladislav Hagara | Komentářů: 18
    včera 13:33 | Komunita

    Byla založena nadace Open Home Foundation zastřešující více než 240 projektů, standardů, ovladačů a knihoven (Home Assistant, ESPHome, Zigpy, Piper, Improv Wi-Fi, Wyoming, …) pro otevřenou chytrou domácnost s důrazem na soukromí, možnost výběru a udržitelnost.

    Ladislav Hagara | Komentářů: 0
    včera 13:00 | Nová verze

    Společnost Meta otevírá svůj operační systém Meta Horizon OS pro headsety pro virtuální a rozšířenou realitu. Vedle Meta Quest se bude používat i v připravovaných headsetech od Asusu a Lenova.

    Ladislav Hagara | Komentářů: 0
    včera 04:33 | IT novinky

    Společnost Espressif (ESP8266, ESP32, …) získala většinový podíl ve společnosti M5Stack, čímž posiluje ekosystém AIoT.

    Ladislav Hagara | Komentářů: 0
    KDE Plasma 6
     (72%)
     (9%)
     (2%)
     (17%)
    Celkem 706 hlasů
     Komentářů: 4, poslední 6.4. 15:51
    Rozcestník

    Dotaz: Využítí pipe v C

    31.8.2020 21:21 steel rock | skóre: 18
    Využítí pipe v C
    Přečteno: 1085×

    Ahoj, potřeboval bych poradit, jak implementovat pipe do C. Jako příklad jsem napsal jednoduchý prográmek

    #include <stdio.h>
    
    int main(int argc, char **argv) {
    	const char size=16;
    	FILE *f;
    	char c,buffer[size];
    	f=fopen(*++argv, "r");
    	
    	int i=0;
    	while((c=getc(f)) != EOF){
    		if (i>=size) break;
    		buffer[i]=c;
    		i++;
    	}
    		
    	printf("%s\n", buffer);
    	
    	fclose(f);
    	return 0;
    }
    

    u kterého funguje

    $ ./programek hello.txt

    hello world

    ale potřeboval bych nějaký kód, ve kterém by fungovalo i

    $ echo "hello world" | ./programek

    hello world

    ...a zkusili jste to vypnout a zapnout?

    Řešení dotazu:


    Odpovědi

    Řešení 3× (xkucf03, Bherzet, steel rock (tazatel))
    31.8.2020 22:42 kvr
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Zjednodušeně:

        f = argc > 1 ? fopen(*++argv, "r") : stdin;

    ... pominu-li různé kontroly na options, jestli je víc argumentů než jeden apod...
    Řešení 1× (steel rock (tazatel))
    31.8.2020 23:16 Bherzet | skóre: 19 | blog: Bherzetův blog
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Případně by se ještě mohlo hodit isatty.
    6.9.2020 18:52 steel rock | skóre: 18
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Děkuji. Tato i předchozí odpověď byly přesně to, co jsem hledal.
    ...a zkusili jste to vypnout a zapnout?
    1.9.2020 09:37 z_sk | skóre: 34 | blog: analyzy
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    stdin - standart input
    stdout - standart output
    stderr - standart error output
    debian.plus@protonmail.com
    1.9.2020 13:17 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    …jak implementovat pipe do C…

    Huh? To, co popisuješ, není dýmka, nýbrž kočka.

    A když už implementovat, tak co třeba

    • neomezovat to na jeden soubor,
    • neomezovat to na 16 znaků,
    • nečíst to po jednom znaku,
    • někdy aspoň trochu hlásit chyby…?

    Takže třeba:

    #include <fcntl.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/types.h>
    #include <unistd.h>
    
    static int copyfd(const int source, const int dest) {
      char buffer[4096];
      for (;;) {
        ssize_t to_write = read(source, buffer, sizeof(buffer));
        if (to_write <= 0) {
          return close(source) == -1 || to_write == -1 ? -1 : 0;
        }
        const char *wbuffer = buffer;
        for (;;) {
          const ssize_t written = write(dest, wbuffer, to_write);
          if (written < 0) {
            close(source);
            return -1;
          }
          to_write -= written;
          if (to_write == 0) break;
          wbuffer += written;
        }
      }
    }
    
    int main(int argc, const char* const* argv) {
      int result = EXIT_SUCCESS;
      if (argc > 1) {
        for (++argv; *argv; ++argv) {
          const int fd = open(strcmp(*argv, "-") == 0
                              ? "/dev/stdin"
                              : *argv,
                              O_RDONLY);
          if (fd == -1) {
            perror(*argv);
            result = EXIT_FAILURE;
            continue;
          }
          if (copyfd(fd, STDOUT_FILENO) == -1) {
            perror(*argv);
            result = EXIT_FAILURE;
          }
        }
      } else {
        if (copyfd(STDIN_FILENO, STDOUT_FILENO) == -1) {
          perror("dýmka");
          result = EXIT_FAILURE;
        }
      }
      return result;
    }
    
    xkucf03 avatar 1.9.2020 14:28 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    nečíst to po jednom znaku

    Přes FILEgetc() se to nečte po jednom, ne?

    $ echo ahoj | strace ./programek
    …
    read(0, "ahoj\n", 4096)                 = 5
    read(0, "", 4096)                       = 0
    …
    write(1, "ahoj\n\n", 6)                 = 6
    …

    (s těmi ostatními připomínkami souhlasím)

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    1.9.2020 21:56 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C

    Jasně, bufferuje se to. Potud fajn.

    Dokonce getc() se může zainlajnovat, pokud ho (kni)hovny rozumně inlajnovatelně definují [[nevím; doufám]].

    Ale ten test na EOF po každém bytu tam prostě přebývat bude; to by musel být hodně zázračný kompilátor, aby tohle zefektivnil na úroveň práce s celými buffery.

    (Když se data tak či tak interpretují a procházejí, je to úplně jedno; stejně se bude na každý byte sahat. Nicméně když to má být jenom dýmka nebo kočka, čtení po znacích není zrovna super. (Vzpomínám si, že Java to kdysi takhle měla, ale to bylo jenom v těch (kni)hovnách, do kterých se člověk proklikal z IDE a které tam byly jenom na ukázku, zatímco v praxi [[praxe == běh mimo debugging]] tam bylo něco kolem JIT + JNI, co takové věci provádělo rozumně.))

    Jendа avatar 1.9.2020 22:19 Jendа | skóre: 78 | blog: Jenda | JO70FB
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Inlajnování getc nevím (tuhle mi někdo vysvětloval že dělat LTO nad celou libc moc nejde), každopádně jednou jsem použil v cyklu fread(..., 1, 1, ...) a bylo to dost pomalé (operace s každým bajtem byla triviální, třeba řekněme sčítání). Overhead se stal zanedbatelným až když jsem freadem četl něco jako 8 bajtů najednou.
    2.9.2020 08:53 z_sk | skóre: 34 | blog: analyzy
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Ono, zalezi to ako kolko das citas. Je rozdiel 6B/s voci 350MB/s. Pri kazdom volani fread dochadza k prepinany do kernelu (zvycajne, ale tiez C lib to trochu cachuje, takze kus menej prepinani), takze to moze zbytocne trochu spomalovat, ak sa to da urobit efektivnejsie.
    debian.plus@protonmail.com
    xkucf03 avatar 2.9.2020 09:13 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše FILE vs. FD
    Pri kazdom volani fread dochadza k prepinany do kernelu (zvycajne, ale tiez C lib to trochu cachuje, takze kus menej prepinani)

    Funkce fread() přece pracuje nad FILE, ne nad surovým FD, takže tam už buffer je a – jak ukazuje strace výše – systémové volání read() se volá méně často.

    Jaký má smysl dělat další buffer v aplikaci? Je to opravdu jen kvůli té efektivnější kontrole na EOF, jak píše Andrej? Nebo je k tomu ještě nějaký jiný důvod?

    Když chci mít buffer v aplikaci, není pak lepší se vykašlat na FILE a pracovat rovnou s FD?

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    2.9.2020 13:25 z_sk | skóre: 34 | blog: analyzy
    Rozbalit Rozbalit vše Re: FILE vs. FD
    Když chci mít buffer v aplikaci, není pak lepší se vykašlat na FILE a pracovat rovnou s FD?
    s FILE su osetrene kadejake signali (takze ak nie si expert) tak je lepsie spracovat s tym. Samozrejme, ak sa da citat po blokov, tak citat po blokov.
    Jaký má smysl dělat další buffer v aplikaci? Je to opravdu jen kvůli té efektivnější kontrole na EOF, jak píše Andrej? Nebo je k tomu ještě nějaký jiný důvod?
    Programoval si nieco? Svet nie je len o http streamoch so stahovanim suborov. Lepsie je, ak prikazy (trebars v nejakej GUI hre) prichadzaju po blokoch. Ak neuplny prikaz, tak sa docita a sparcuje. Zas aj sietovy protokol funguje ze sa posiela minimalne po blokoch (ak chces poslat bajt po siety, tak to stoji rovnako ak posles naraz 5B (po MTU).

    rovno pristup je citlevejsie na chyby - nejake chyba = poslanie signal() od OS (co casto byva kill aplikacie).
    debian.plus@protonmail.com
    2.9.2020 09:18 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Pri kazdom volani fread dochadza k prepinany do kernelu

    To právě při testu fread(..., 1, 1, ...) nebude platit ani zdaleka. Tam bude spíš jiný problém, protože fread() je obecná funkce, která bude mít pro speciální případ čtení jednoho byte oproti getc() nebo fgetc() dost velký overhead.

    Pokud se těch dat kopíruje opravdu hodně a jde o výkon, tak už může podle situace být výhodnější použít třeba něco jako mmap(), splice() nebo sendfile().

    2.9.2020 09:51 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Schválně jsem si to teď změřil. Rozdíl mezi fgetc() a getc() je zanedbatelný, fread(..., 1, 1, ...) je skoro pětkrát pomalejší - volání jádra je samozřejmě stejně. Další zrychlení (asi na čtyřnásobek) se dá docílit použitím _unlocked verzí, s tím už jsem se s fgetc_unlocked() a getc_unlocked() dostal asi na 1.7-1.8 GB/s (4GB soubor na tmpfs).
    2.9.2020 13:26 z_sk | skóre: 34 | blog: analyzy
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    skus aj cez write().
    debian.plus@protonmail.com
    2.9.2020 15:39 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Využítí pipe v C

    Tady jsou výsledky pro všechny možné varianty na 4GB souboru, kromě read_1, kde jde o extrapolaci z výsledku pro 1GB soubor (pouštět to znovu na čtyřikrát větší se mi opravdu nechtělo).

    Je to načtení celého souboru a aby se vyloučily nějaké špinavé triky optimalizace, udělá po bytech xor. Soubor je samozřejmě na tmpfs. Čte se to pomocí fgetc(), getc(), fread() a read(). U libc funkcí navíc i s unlocked variantami. U fread() a read() se čte po blocích o 1B, 4KB nebo 1MB.

      fgetc                8.315s     492.6MB/s
      fgetc_unlocked       2.237s    1831.2MB/s
      getc                 8.247s     496.7MB/s
      getc_unlocked        2.236s    1831.5MB/s
      fread_1             70.633s      58.0MB/s
      fread_4K             1.521s    2693.5MB/s
      fread_1M             1.585s    2584.1MB/s
      fread_unlocked_1     5.439s     753.1MB/s
      fread_unlocked_4K    1.493s    2743.5MB/s
      fread_unlocked_1M    1.644s    2491.6MB/s
      read_1             750.744s       5.5MB/s
      read_4K              0.531s    7714.1MB/s
      read_1M              0.400s   10237.2MB/s
    

    Zajímavé výsledky jsou víceméně jen dva:

    • {f,}getc_unlocked() není nijak propastně pomalejší než fread() nebo fread_unlocked() s rozumnou velikostí bloku
    • fread() s příliš velkým blokem může být i pomalejší než s 4KB (totéž platí i pro read(), ale tam je optimální velikost větší)

    Zbytek je podle očekávání:

    • read() po 1B vychází naprosto tragicky
    • rozdíl mezi locked a unlocked stdio je výrazný u čtení po bytech, u delších bloků moc ne
    • libc funkce mají oproti syscallu nějakou tu režii, takže jde-li o výkon "na krev", může stát za to použí low level API (a nakonec třeba i něco jiného než read())
    • bude-li se to číst z běžného disku, bude nakonec jedno, co se použije, kromě teoretických extrémů (fread_1, read_1)
    1.9.2020 14:28 z_sk | skóre: 34 | blog: analyzy
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Toto "/dev/stdin" robi zbytocnu zavistlost na udev fs /dev a tym padom zbytocne zrusenie multiplatformovnosti.
    debian.plus@protonmail.com
    1.9.2020 16:31 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C

    Ano, tak už to bývá, že kočka není multiplatformní. Vnější projevy kočky multiplatformní jsou a musí být, ale kočka samotná ani moc ne.

    To /dev/stdin je tam — zcela záměrně — kvůli chování podobnému cat v podivných okrajových případech. Třeba cat - -, cat - - - a tak podobně. Samozřejmě je to okrajová hloupost a neexistuje jedno jediné správné chování v takové situaci, takže nezbývá než zvolit prostě nějaké chování.

    xkucf03 avatar 1.9.2020 18:01 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: Využítí pipe v C

    Nebude STDIN_FILENO (či stdin) přenositelnější než /dev/stdin?

    Navíc u toho STDIN_FILENO používáš již otevřený FD.

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    1.9.2020 18:18 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Podle toho komentáře je to asi kvůli napodobení chování "cat - -" při spuštění z terminálu (je mu potřeba ukončit vstup dvakrát). Ale i to by asi šlo napsat bez spoléhání na /dev/stdin
    1.9.2020 18:36 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C

    Já si chování kočky představuju tak, že bez parametrů bere stdin a posílá to na stdout, bez velkého přemýšlení, zatímco s parametry vždycky něco otevírá (od čehož se bude odvíjet taky počáteční stav věcí kolem lseek() a tak.

    Samozřejmě ten případ s několika pomlčkami nedává rozumný smysl, takže asi nestojí za to přehnaně se jím zabývat.

    Jo, šlo by to klidně i jenom pomocí STDIN_FILENO a bez /dev/stdin. Pokud je standardní vstup seekovatelný, můžu si zapamatovat pozici, někam to převinout a kdesicosi. Pokud standardní vstup není seekovatelný, je úplně jedno, jestli ho znovu otevírám nebo ne; výsledek už nemůže být stejný. (Například když je to dýmka.)

    Že používám už otevřený deskriptor, to je normální. Můžu třeba něco rozečíst a potom to dočíst kočkou. Například: Vypiš všechny řádky z /etc/passwd pod uživatelem ntp.

    (
      while IFS=: read user discard; do
        [[ "$user" = 'ntp' ]] && break
      done
      cat
    ) < /etc/passwd
    

    Tady^^^ se využívá toho, že vstup už je otevřený a v nějaké pozici.

    1.9.2020 14:37 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Využítí pipe v C
        ssize_t to_write = read(source, buffer, sizeof(buffer));
        if (to_write <= 0) {
          return close(source) == -1 || to_write == -1 ? -1 : 0;
        }
    

    EINTR anyone?

    1.9.2020 16:18 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C

    Ne. Až tomu bude chtít uživatel opravdu posílat signály, pak ať si to ošetří. Do té doby je to úplně jedno.

    A ani pak ať to raději explicitně neošetřuje — k tomu máme SA_RESTART, ne?

    Implicitně je reakce na podstatné signály celkem předvídatelná — u SIGHUP / SIGBUS / SIGPIPE (tedy u toho, co opravdu v praxi může přijít samo od sebe a má to význam) beztak nejde o stav, ve kterém by se mělo něco zkoušet znova.

    U ostatních signálů platí, že EINTR (nebo raději a lépe SA_RESTART) budu řešit jedině tehdy, pokud budu mít aspoň jeden netriviální handler signálu.

    1.9.2020 16:29 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Podle vás je naprosto v pořádku, že když se ten program stopne (např. pomocí Ctrl-Z) a pak nechá opět pokračovat, případně dostane nějaký defaultně ignorovaný signál jako SIGWINCH (protože se změní velikost terminálu), tak skončí "chybou"? Podle mne ne.
    1.9.2020 17:16 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C

    V pořádku je to, co neodporuje specifikaci. Bez specifikace je v pořádku téměř cokoliv.

    Zkoušel jste vůbec něco z uvedeného? Nebo jenom zbytečně střílíte od pasu a úplně vedle? To druhé, že jo! :-D

    Ne, neselže to na SIGWINCH, protože implicitní akce je Ign. EINTR se týká jen případů, kdy proběhne handler. To není tento případ.

    Jednoduchý test 1: ./program /dev/zero > /dev/null (a změnit velikost okna, a zkusit Ctrl+Z a pak fg)

    Jednoduchý test 2: ./program (a psát ptákoviny na terminálu a změnit mezitím velikost okna a párkrát zkusit Ctrl+Z a fg)

    Ne a ne selhat, co???

    No a pak třeba poslat kill -USR1 ... Teprve tohle ten proces (celkem správně) zabije, protože implicitní akce je Term.

    Jak už jsem psal níže: „Potřeba“ ošetřit EINTR pramení ze všeho nejčastěji z nepochopení problematiky.

    Jednoduchý test 3: Pomocí sigaction() si nastavte jednoduchý handler na SIGWINCH. Teprve s handlerem to odletí na SIGWINCH —> EINTR. S implicitní akci (Ign) rozhodně ne.

    Takže résumé ještě jednou: Uživatel si EINTR ošetří až teprve tehdy, kdy bude chtít posílat a ošetřovat signály. Nebo se na to (raději a lépe) vybodne a nastaví si SA_RESTART. Ale to až bude používat vlastní handlery; dřív to ani nejde.

    1.9.2020 17:38 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Ne a ne selhat, co???

    A zkusil jste se taky podívat pomocí strace, co přesně se tam děje? Viděl byste totiž něco jako

    24241 read(0, 0x7ffcf84071d0, 4096)     = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
    24241 --- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
    24241 read(0, 0x7ffcf84071d0, 4096)     = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
    24241 --- SIGWINCH {si_signo=SIGWINCH, si_code=SI_KERNEL} ---
    24241 read(0, 0x7ffcf84071d0, 4096)     = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
    24241 --- SIGCONT {si_signo=SIGCONT, si_code=SI_USER, si_pid=22361, si_uid=1000} ---
    24241 read(0, 0x7ffcf84071d0, 4096)     = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
    

    Jestli chcete psát své programy tak, aby byla funkčnost závislá na tom, že vždy poběží na systému, který bude nastavovat flagy přesně tak, jako ten jeden, na kterém jste si to empircky vyzkoušel, je to váš problém. Jen to, prosím, neučte ostatní.

    EINTR se týká jen případů, kdy proběhne handler.

    Ne, u read() se EINTR se týká jakéhokoli případu, kdy je syscall přerušen signálem, aniž by přečetl data. Máte to napsané i v manuálové stránce, možná by bylo lepší si ji přečíst, než začnete psát věci jako

    „Potřeba“ ošetřit EINTR pramení ze všeho nejčastěji z nepochopení problematiky.

    Jinak taková věta vyzní poněkud ironicky.

    1.9.2020 18:47 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    A zkusil jste se taky podívat pomocí strace, co přesně se tam děje? Viděl byste totiž něco jako

    Napadlo vás někdy, že syscally z strace jsou interní implementační detail, který se může a nemusí promítnout do výsledného chování toho API v C? ;-)

    Máte to napsané i v manuálové stránce, možná by bylo lepší si ji přečíst

    Nemám.

    Takže nejenom střílíte od pasu, ale ani tu manuálovou stránku jste si nepřečetl. Výborně! Tak tohle prosím hlavně neučte ostatní.

    Pojďme se, prosím, podívat do té manuálové stránky (kterékoliv, která pojednává o EINTR).

    EINTR  While blocked waiting to complete an open of a slow device (e.g., a FIFO; see fifo(7)),
           the call was interrupted by a signal handler; see signal(7).
    

    Co tam^^^ stojí? Signal handler.

    …handler…

    …handler…

    …handler…

    Už? "signal handler" != "signal"

    1.9.2020 19:22 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Napadlo vás někdy, že syscally z strace jsou interní implementační detail, který se může a nemusí promítnout do výsledného chování toho API v C? ;-)

    A napadlo někdy vás, že jste prostě jen měl štěstí a zdědil SA_RESTART flag od bashe?

    Nemám. Takže nejenom střílíte od pasu, ale ani tu manuálovou stránku jste si nepřečetl.

    Četl - a na rozdíl od vás dostatečně pozorně. Zkusme začít s read(3p), tj. oficiální posixovou dokumentací:

    EINTR The read operation was terminated due to the receipt of a signal, and no data was transferred.

    Ať čtu, jak čtu, žádné slovo "handler", bez ohledu na tučnost nebo velikost, tam není.

    No a když se podíváme na read(2), tedy linuxovou verzi:

    EINTR The call was interrupted by a signal before any data was read; see signal(7).

    Zase žádné handler, bez ohledu na font. V signal(7) sice slovo handler je, ale z kontextu je zřejmé, že tím není myšlen pouze vlastní handler, který by si proces zaregistroval pomocí signal() nebo sigaction(), ale handler obecně, což zahrnuje i případ ignorovaného signálu.

    1.9.2020 21:34 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Napadlo vás někdy, že syscally z strace jsou interní implementační detail, který se může a nemusí promítnout do výsledného chování toho API v C? ;-)

    A napadlo někdy vás, že jste prostě jen měl štěstí a zdědil SA_RESTART flag od bashe?

    Vaříte z vody. Už zase jste to totiž nedočetl:

    A child created via fork(2) inherits a copy of its parent's signal dispositions. 
    During an execve(2), the dispositions of handled signals are reset to the default; the dispositions of ignored signals are left unchanged.
    

    S tím čtením prostě nemůžete skončit v půlce, po první větě. :-D Je třeba to dočíst.

    Nebo, když už v tom tápete, můžete si to přece snadno vyzkoušet, ne? Tak, jestlipak se SA_RESTART dědí?

    #define _POSIX_C_SOURCE 200809L
    #include <signal.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    
    static void print_sigaction(const char* name,
                                const struct sigaction* sa) {
      printf("%s %s SA_RESTART\n",
             name,
             sa->sa_flags & SA_RESTART ? "has" : "doesn't have");
    }
    
    static void useless(int sig) {
      puts(strsignal(sig));
    }
    
    int main(int argc, char* const* argv) {
      struct sigaction old_sa;
      if (argc == 1) {  // BEFORE exec
        const struct sigaction new_sa = {
          .sa_handler = useless,
          .sa_flags = SA_RESTART,
        };
        if (sigaction(SIGWINCH, &new_sa, &old_sa) == -1) {
          perror(argv[0]);
          return EXIT_FAILURE;
        }
        print_sigaction("old sigaction BEFORE exec", &old_sa);
        print_sigaction("new sigaction BEFORE exec", &new_sa);
        char* const one_empty[] = {argv[0], "", NULL};
        if (execv(argv[0], one_empty) == -1) {
          perror(argv[0]);
          return EXIT_FAILURE;
        }
      } else if (argc == 2) {  // AFTER exec
        if (sigaction(SIGWINCH, NULL, &old_sa)) {
          return EXIT_FAILURE;
        }
        print_sigaction("old sigaction AFTER exec", &old_sa);
      } else {
        return EXIT_FAILURE;
      }
      return EXIT_SUCCESS;
    }
    

    Kvízová otázka za 10 bodů: Co tohle^^^ vypíše?

    old sigaction BEFORE exec doesn't have SA_RESTART
    new sigaction BEFORE exec has SA_RESTART
    old sigaction AFTER exec doesn't have SA_RESTART
    

    Pro příště: Nevymýšlejte si, prosím, ptákoviny. :-) Ptákoviny (jako že se dědí SA_RESTART) se snadno vymýšlejí, ale obtížně vyvracejí, protože to můžou být přece jen okrajové případy a signal disposition může znít příliš vágně. Příští tvrzení tohoto druhu bych prosil s manuálovou stránkou (bez vynechaného kontextu) a se snippetem, který to ukazuje. ;-)

    Nemám. Takže nejenom střílíte od pasu, ale ani tu manuálovou stránku jste si nepřečetl.

    Četl - a na rozdíl od vás dostatečně pozorně. Zkusme začít s read(3p), tj. oficiální posixovou dokumentací:

    EINTR The read operation was terminated due to the receipt of a signal, and no data was transferred.

    Ať čtu, jak čtu, žádné slovo "handler", bez ohledu na tučnost nebo velikost, tam není.

    Takže ani tu POSIXovou stránku neinterpretujete správně, jak jste se koneckonců už sám přesvědčil experimentem, že? :-)

    Tentokrát vám unikl přesný význam pojmu receipt of a signal; do této kategorie se implicitní akce Ign nepočítá.

    Výmluvné jsou také některé kousky textu, které najdete v man 7 signal:

    Interruption of system calls and library functions by signal handlers
        If a signal handler is invoked while a system call or library function call is blocked, then either:
        ...
    

    Klíčová slova: handler, invoked

    No a když se podíváme na read(2), tedy linuxovou verzi:

    EINTR The call was interrupted by a signal before any data was read; see signal(7).

    Tedy najednou má specifická linuxová verze (o které jste se už sám přesvědčil, že je nepřesná) přednost? Jenže o pár komentářů výše jste napsal toto:

    Jestli chcete psát své programy tak, aby byla funkčnost závislá na tom, že vždy poběží na systému, který bude nastavovat flagy přesně tak, jako ten jeden, na kterém jste si to empircky vyzkoušel…

    Aha? Jenže najednou má podle vás linuxová verze manuálové stránky jakousi váhu? Nezměnil jste nějak rychle názor, doslova obratem? :-D

    Zase žádné handler, bez ohledu na font. V signal(7) sice slovo handler je, ale z kontextu je zřejmé, že tím není myšlen pouze vlastní handler, který by si proces zaregistroval pomocí signal() nebo sigaction(), ale handler obecně, což zahrnuje i případ ignorovaného signálu.

    Proto jsou ty POSIXové stránky většinou lepší než linuxové. Rozlišují velmi důsledně pojmy action, handler a signal. To jsou velmi důležité nuance.

    Upřímně řečeno, já jsem opravdu (ale opravdu (ale opravdu ...)) ten poslední, komu má smysl cpát tohle profláknuté EINTR-náboženství. Jsem na něj alergický hlavně proto, že zbytečné rádoby-ošetření EINTR vyhazuju z kódu už asi tak dekádu. Vyhazuju to vidlema. Vyhazuju to oknem. Vyhazuju to vraty. Splachuju to do hajzlu. Ale ono se to vždycky vrátí komínem, protože někdo (už zase) nepochopil, že POSIX je navržený tak, aby se s tím API snadno / rychle / korektně programovalo, nikoliv tak, aby se člověk musel na 50 řádcích věnovat ošetření signálů, než si přečte jeden soubor.

    1.9.2020 22:32 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Využítí pipe v C

    OK, nezdědí se, tak za to holt může glibc, ale to je ve výsledku úplně jedno. Pořád to není garantované chování, na které by se bylo možné spolehnout.

    Takže ani tu POSIXovou stránku neinterpretujete správně, jak jste se koneckonců už sám přesvědčil experimentem, že? :-)

    Experimentem se můžu přesvědčit nanejvýš o tom, že se v jednom konkrétním případě (nebo několika) ten syscall defaultně restartuje, i když to tak explicitně nenastavím. Na rozdíl od vás mi takový experiment nestačí k závěru, že se na to dá spoléhat vždy a všude.

    Tentokrát vám unikl přesný význam pojmu receipt of a signal; do této kategorie se implicitní akce Ign nepočítá.

    Vůbec ne, to je jen vaše interpretace. A strace vás usvědčuje z omylu, protože je z něj naprosto jasně vidět, že ten syscall přerušen byl a vy jste to nepoznal jen proto, že byl restartován.

    Tedy najednou má specifická linuxová verze (o které jste se už sám přesvědčil, že je nepřesná) přednost? Nezměnil jste nějak rychle názor, doslova obratem?

    A to jste si vymyslel jakým myšlenkovým pochodem? Jen jsem vám ukázal, že obě verze manuálové stránky (1) v rozporu s vaším trvzením EINTR zmiňují a (2) o žádném handleru nemluví. A pokud, ja sám tvrdíte, upřednostňujete posixovou dokumentaci tak to signal(7) není.

    že zbytečné rádoby-ošetření EINTR vyhazuju z kódu už asi tak dekádu. Vyhazuju to vidlema. Vyhazuju to oknem. Vyhazuju to vraty. Splachuju to do hajzlu.

    Inu, jen si vyhazujte, splachujte, jak je ctěná libost. Jen se pak holt nedivte, až vás s tím někde vyhodí maintainer, který na rozdíl od vás nechce spoléhat na to, že vaše emprická zkušenost ("zkusil jsem to a funguje mi to") má univerzální platnost.

    Mně může být koneckonců jedno, co si děláte na svém písečku, to je váš problém. Pokud vás nepřesvědčil ani naprosto jednoznačný výstup strace, pak asi nemá smysl, abych se o cokoli snažil. Žijte si blaze.

    1.9.2020 23:03 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Vůbec ne, to je jen vaše interpretace. A strace vás usvědčuje z omylu, protože je z něj naprosto jasně vidět, že ten syscall přerušen byl a vy jste to nepoznal jen proto, že byl restartován.

    Zdá se, že nechápete, že to API nepracuje (navenek) s konceptem syscallů (které POSIXové API jo?) a že interně si může bez vašeho vědomí (ne)používat syscally, jak (ne)chce. No, tak to prostě je. :-)

    A to jste si vymyslel jakým myšlenkovým pochodem? Jen jsem vám ukázal, že obě verze manuálové stránky (1) v rozporu s vaším trvzením EINTR zmiňují a (2) o žádném handleru nemluví. A pokud, ja sám tvrdíte, upřednostňujete posixovou dokumentaci tak to signal(7) není.

    Obě manuálové stránky jsou v souladu s mým tvrzením. Že jste je nepochopil a/nebo nedočetl, to už není můj problém. ;-)

    Inu, jen si vyhazujte, splachujte, jak je ctěná libost. Jen se pak holt nedivte, až vás s tím někde vyhodí maintainer, který na rozdíl od vás nechce spoléhat na to, že vaše emprická zkušenost ("zkusil jsem to a funguje mi to") má univerzální platnost.

    Nebojte se, nevyhodí. Chápe totiž psaný text, chápe, jak tohle API funguje, chápe, jak tenhle svět funguje, atd.

    Mně může být koneckonců jedno, co si děláte na svém písečku, to je váš problém. Pokud vás nepřesvědčil ani naprosto jednoznačný výstup strace, pak asi nemá smysl, abych se o cokoli snažil. Žijte si blaze.

    Jednoznačný výstup strace? To má být vtip? Vy opravdu nechápete rozdíl mezi rozhraním a implementací? :-D To myslíte fakt vážně? Uf. To snad ne.

    1.9.2020 23:18 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Jak už jsem řekl: vzdávám to, dělejte si co chcete.
    2.9.2020 19:14 kralyk z abclinuxu | skóre: 29 | blog:
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Tentokrát vám unikl přesný význam pojmu receipt of a signal; do této kategorie se implicitní akce Ign nepočítá.
    A odkázal bys pls, kde je tohle v POSIXu deklarováno?

    Osobně bych taky očekával, že pokud jsem si nenastavil signal handlery, neměl by EINTR nastat, ale zajímalo by mě, jestli to POSIX skutečně takhle říká.

    No jinak ale samozřejmě je tu stále ten argument, že i když program aktuálně žádný signal handlery nemá, někdo může přidat handler v budoucnu a pak procházet kód a hledat syscally je opruz. (Už jsem to musel dělat na netriviálním SW a není to dobrý.)
    2.9.2020 20:20 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Tentokrát vám unikl přesný význam pojmu receipt of a signal; do této kategorie se implicitní akce Ign nepočítá.
    A odkázal bys pls, kde je tohle v POSIXu deklarováno?

    Osobně bych taky očekával, že pokud jsem si nenastavil signal handlery, neměl by EINTR nastat, ale zajímalo by mě, jestli to POSIX skutečně takhle říká.

    SIG_IGN: Ignore signal.
    Delivery of the signal shall have no effect on the process.

    Tohle^^^ je implicitní nastavení třeba zrovna pro SIGWINCH. Kdyby se procesu zničehonic přerušilo blokující volání s chybou EINTR, byl by to setsakra veliký effect. Specifikace ovšem nařizuje no effect.

    Nikde to POSIX neříká zpříma v jedné větě. Je to rozprostřené v drobných vágních náznacích na mnoha místech v popisu signálů. (Proto v tom má tolik lidí nejasnosti a proto se tyhle „chyby“ (ošetření chyb, které nenastanou) vidí tak často.)

    No jinak ale samozřejmě je tu stále ten argument, že i když program aktuálně žádný signal handlery nemá, někdo může přidat handler v budoucnu a pak procházet kód a hledat syscally je opruz. (Už jsem to musel dělat na netriviálním SW a není to dobrý.)

    Na tohle mám jednoduchý protiargument: Zbytečné ošetření neexistujícího EINTR přidává netestovaný / netestovatelný kód, který nikdy neběžel. Neměl jak. Někde tam sedí a čeká, může být úplně špatně, může se zacyklit napořád, může leakovat paměť, může to celé shodit.

    Pár let to takhle funguje. Pak někdo přidá handler na SIGWINCH… (Nebo na jiný implicitně ignorovaný signál.) Najednou se vrátí chyba EINTR. A celé to zařve, spousta věcí bude špatně, třeba to nezopakuje správně zápis a poškodí integritu dat atd. A bude se to fakt špatně debuggovat.

    Lepší scénář: EINTR zprvu nikdo neošetřuje — což je v nepřítomnosti handlerů správně —, později se přidá handler signálu, nastane EINTR a celé to korektně odletí s chybou EINTR. V té chvíli se bude (teprve) řešit osetření EINTR — správné, testovatelné, projde valgrindem při změnách velikosti okna atd. A od té doby to bude fungovat šťastně a spokojeně se SIGWINCH —> EINTR, bez ošklivých překvapení.

    2.9.2020 22:08 kralyk z abclinuxu | skóre: 29 | blog:
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Zbytečné ošetření neexistujícího EINTR přidává netestovaný / netestovatelný kód, který nikdy neběžel. Neměl jak.
    Myslíš ten loop? Vždyť je to poměrně velmi jednoduchá věc, nakterou by nemělo být velký problém napsat makro (v GNU libc už existuje), to otestovat a pak prostě nasadit víceméně kdekoliv. Nebo v čem tam vidíš tu kompliaci?
    Lepší scénář: EINTR zprvu nikdo neošetřuje — což je v nepřítomnosti handlerů správně —, později se přidá handler signálu, nastane EINTR a celé to korektně odletí s chybou EINTR.
    Jak celé to korektně odletí? Ten EINTR může nastat někde kdesi daleko v kódu třeba někdy o roky později. Jak se dozvíš, na všech místech v programu (který může být rozsáhlý), kde by mohl nastat EINTR, je tato možnost správně ošetřena?

    Např. bys mohl spouštět testy a u toho mít v test harnessu nějaký background thread, který bude spamovat signály. Všimni si ale, že tím se zároveň řeší i tvůj problém s netestovaným/netestovatelným kódem.
    2.9.2020 23:52 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Např. bys mohl spouštět testy a u toho mít v test harnessu nějaký background thread, který bude spamovat signály. Všimni si ale, že tím se zároveň řeší i tvůj problém s netestovaným/netestovatelným kódem.

    Tak potom bych vůbec nic nenamítal a všechno by bylo v nejlepším pořádku. :-)

    Jen jsme se tím dostali příliš daleko od snippetu v mém původním komentáři, co do rozsahu a celkové složitosti příslušného softwaru.

    Že něco korektně odletí, tím myslím, že to ohlásí rozumnou chybu, zavře správně (aspoň) všechno, co nezavírá samotný konec programu (různé IPC prostředky), nenadělá paseku v souborech nebo jiných „perzistentních“ datech a neskončí karambolem typu SIGSEGV, SIGILL ani ničím podobným. (SIGABRT je tak na hraně; pokud to má někdo dobře ošetřené, tak fajn.)

    Jendа avatar 1.9.2020 22:29 Jendа | skóre: 78 | blog: Jenda | JO70FB
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Dobré vlákno, ale nechtěl bys jen tak bokem zmínit, jak by to tedy mělo být správně? :-) Jde tedy o to, že read/write můžou vrátit 0 nebo -1, i když je všechno v pořádku (jenom přišel signál), a tedy ho stačí zavolat znovu a zápis/čtení proběhne?

    Takže pro read by podmínka měla být
    ssize_t r = read(...);
    if (r == 0) // konec souboru
    if (r < 0 && errno != EINTR) // chyba
    // jinak pokračovat ve čtení na pozici buf+r
    A pro write
    ssize_t r = write(...);
    if (r <= 0 && errno != EINTR) // chyba
    // jinak pokračovat v zápisu na pozici buf+MIN(0,r) (fakt? protože r může být -1 a errno EINTR?)
    ?
    1.9.2020 22:59 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Využítí pipe v C

    Pokud dostanu chybu a errno je EINTR, pak se "nic nestalo" a typická akce je zopakovat to volání se stejnými parametry. V glibc je na to makro TEMP_FAILURE_RETRY():

      ret = TEMP_FAILURE_RETRY(read(...));
    

    ten read() opakuje, tak dlouho, dokud buď neuspěje nebo nedostane jinou errno než EINTR. Pokud to budeš dělat ručně (a s jednou smyčkou), tak je prostě potřeba v případě -1/EINTR neupdatovat pozici (ani zbývající délku).

    if (r <= 0 && errno != EINTR)

    Na tohle taky pozor. Standard pouze stanoví, že skončí-li volání chybou, nastaví se errno na odpovídající hodnotu, ale neříká nic o tom, co se s errno stane, pokud volání uspěje. Empirická zkušenost je taková, že obvykle zůstane beze změny, a už jsem párkrát viděl kód, který na to spoléhal (nastavil před voláním errno na nulu a testoval hodnotu po návratu). Obecně to ale není zaručeno a i když jsem takovou implementaci v praxi neviděl, teoreticky je možné, že hodnota po úspěšném volání nebude ani nula, ani původní.

    1.9.2020 23:18 Bherzet | skóre: 19 | blog: Bherzetův blog
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Standard pouze stanoví, že skončí-li volání chybou, nastaví se errno na odpovídající hodnotu, ale neříká nic o tom, co se s errno stane, pokud volání uspěje.
    Takže by to mohlo nastavit errno = EINTR po neúspěšném volání a po úspěšném ho nezměnit, tzn. že by TEMP_FAILURE_RETRY vedl na nekonečnou smyčku?
    1.9.2020 23:21 Bherzet | skóre: 19 | blog: Bherzetův blog
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Sorry, blbost, ono ještě záleží na tom, co vrací read.
    1.9.2020 23:22 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: Využítí pipe v C

    Ne, to makro testuje obě podmínky, tj. opakuje jen pokud se argument vyhodnotí jako -1 a navíc je errno rovno EINTR. Na mém systému např. vypadá takhle (je v /usr/include/unistd.h):

    /* Evaluate EXPRESSION, and repeat as long as it returns -1 with `errno'
       set to EINTR.  */
    
    # define TEMP_FAILURE_RETRY(expression) \
      (__extension__                                                              \
        ({ long int __result;                                                     \
           do __result = (long int) (expression);                                 \
           while (__result == -1L && errno == EINTR);                             \
           __result; }))
    
    1.9.2020 23:24 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C

    Jediná berná mince je návratová hodnota z příslušné funkce. Při/po úspěchu se na errno nesahá.

    1.9.2020 23:16 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C

    0 z read() je EOF, tedy v podstatě the ultimate úspěch.

    0 z write() při nenulové délce je snad leda chyba v kernelu nebo v (kni)hovnách. Ale já se v počítačích nevyznám, tak nevím.

    -1 z read() nebo write() je

    • nenávratný průser, pokud jsem si nehrál s handlery; v tom případě to můžu (pro daný file descriptor) zabalit, prostě se to posralo.
    • možná jenom EINTR, pokud jsem si hrál s handlery a někde jsem si nějaký netriviální handler na daný signál nastavil a nemám signál zamaskovaný a dostal jsem ten signál, handler proběhl atd. Jenže kdybych si byl radši nastavil SA_RESTART, tak jsem se touhle věcí nemusel vůbec zabývat. (Jinak -1 vždycky říká, že se nezapsalo nic, takže po EINTR se to má znova zkusit se stejnými parametry. Ale megafonem všem místo toho doporučuju: SA_RESTART.)
    1.9.2020 23:20 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    0 z read() je EOF, tedy v podstatě the ultimate úspěch.

    (*) při nenulové délce. (Než aby mě někdo zase bral za slovo, radši se za něj vezmu sám.)

    xkucf03 avatar 1.9.2020 18:09 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše LetsEncrypt a padání při změně velikosti okna
    protože se změní velikost terminálu

    Tahle hrůza byla (nebo možná ještě je) v LetsEncrypt, když se používá v manuálním režimu. (jasně, certifikáty by se měly obnovovat automaticky, ale to teď nechme stranou) To si takhle člověk projde přes X domén, vykopíruje si jejich kódy, odskočí si do jiného terminálu… a když se vrátí zpět, tak zjistí, že LetsEncrypt spadl (kvůli změně okna – třeba při otevřeném vyhledávacím panelu v Konsoli) a je třeba začít znova.

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    1.9.2020 18:53 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: LetsEncrypt a padání při změně velikosti okna

    Tahle hrůza postihuje kdekoho, kdo si zbytečně a neopatrně hraje s handlery. :-) Někdy se to týká skriptovacích jazyků, někdy zase některých nastavení ncurses atd. atp.

    Možnosti jsou v podstatě dvojí: Buď z toho udělat téměř neinteraktivní utilitu, bez chytrých promptů, editace v terminálu atd., a nechat všechno v implicitní konfiguraci; pak to zkrátka funguje, podle očekávání. Nebo dělat různé triky se správou terminálu a se signály s ní souvisejícími. To je sice bezva, jenže pak se musí všechno nastavit od začátku do konce, nikoliv jen napůl.

    xkucf03 avatar 1.9.2020 19:10 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: LetsEncrypt a padání při změně velikosti okna

    Ona ta chyba dost možná není v těch aplikacích, ale ve výchozím chování Pythonu nebo nějaké jeho knihovny…

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    1.9.2020 21:41 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: LetsEncrypt a padání při změně velikosti okna

    To rozhodně. Ale těžko to těm (kni)hovnám vyčítat, když takový interpret Pythonu má single-source portabilitu přes velké N platforem. Pak tam možná bude něco jako ncurses přes swig nebo cojávímco a pak už není vůbec jasné, co se tam děje za paseku.

    (Jinak samozřejmě je to bug, to bezesporu, když se to takhle posírá. Nikdy jsem u běžící Let's Encrypt nezkoušel změnit velikost terminálu a ani to zkoušet nehodlám, no nicméně tohle přece musí ustát bez debat. Přesně jako (výše uvedený) kód, který si se signály vůbec nehraje a jen spoléhá na to, že implicitně je vše nastavené rozumně (což je!).

    (Protože upřímně, kdo by v praxi chtěl, aby nějaká dvacetiřádková prasárna v C, kterou narychlo sesmolil jako prototyp, náhodně zařvala kvůli SIGWINCH? (No nehlaste se všichni.))
    1.9.2020 15:36 z_sk | skóre: 34 | blog: analyzy
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    A ak nie je nevyhnutne pouzivat read(), write(), close(), tak ma (urcite zaciatocnik) pouzivat s prefixom f. Napr. s f funckie osetruju vynimky signal(7).
    debian.plus@protonmail.com
    1.9.2020 16:22 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Napr. s f funckie osetruju vynimky signal(7).

    Což není potřeba ošetřovat (resp. „potřeba“ nejčastěji plyne z nepochopení problematiky), ale jinak souhlasím, že používat čistě pro dobrý pocit (a malý kousek portovatelnosti navíc) funkce f.* je správné.

    2.9.2020 13:39 z_sk | skóre: 34 | blog: analyzy
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Ono bavit sa ci fwrite() alebo write() je mozno usmevne pri jednoduchych prikladov. I mne sa pacili write(), alebo ked som potom dostaval signaly, tak som usudil, ze fwrite je fajn. Daco som v zivote aj C programoval a upravoval prehladavac, tak vstupuje aj clovek do neznamych vod - nevie co tam presne je a co vsetko moze nastat (a nechce sa mu kompletne studovat kod). Tak naco si robit problemy.

    Ak chceme efektivitu, mozme rovno pouzivat API kernelu resp. pisat v ASM
    debian.plus@protonmail.com
    2.9.2020 19:59 rastos | skóre: 62 | blog: rastos
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Páni, páni! Oceňujem vašu hlbokú znalosť systému a runtime knižnice ako aj dôslednosť v ošetrovaní hraničných situácií, ale nemyslíte, že by vaša odpoveď mala zodpovedať úrovni toho, kto položil otázku?
    2.9.2020 20:25 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C

    Tak já jsem odpověděl konkrétním kódem, který si může tazatel spustit.

    Nemůžu za to, že pak (už zase) někdo vytáhl na světlo EINTR pověru.

    6.9.2020 19:17 steel rock | skóre: 18
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    Andreji, sice jste odpověděl, ale nemusíte nutně dělat chytrého. Já jsem psal, že uvádím kód jako příklad a opravdu jsem se v příkladu nezabýval všemi ošetřeními a velikostí bufferu (text "hello world" se tam vejde). Nechci do poradny dávat lidem moc rozsáhlý kód, aby se s ním museli přelouskávat, když jsem chtěl stejně radu, jak tam přidat dva nebo tři příkazy. Přesto děkuji za pomoc, po vyřešení mého problému byla diskuze zajímavé čtení :D
    ...a zkusili jste to vypnout a zapnout?
    7.9.2020 09:56 Andrej | skóre: 51 | blog: Republic of Mordor
    Rozbalit Rozbalit vše Re: Využítí pipe v C

    Když už prý „dělám chytrého“, tak dobrá, začnu „dělat chytrého“:

    Na původním příkladu nevadilo, že byl krátký — to by byla velká přednost, kdyby fungoval.

    Jenže on nefunguje — nejen kvůli omezení velikosti souboru na 16 bytů; to nechme stranou. Horší je, že dělá nedefinované operace s neinicializivanou pamětí.

    Jak printf() zjistí, kde končí string? Co za string zapíše koncovou nulu? Nic. :-( Nula tam může být díky šťastné náhodě. Za 16. bytem bufferu už je to spíš výhra v loterii, že to neodletí (sahání na blíže neurčenou část zásobníku). (Na 17. byte (a možná dál) sáhne printf() pokaždé, když vstup bude mít aspoň 16 bytů nebo když buffer nebude šťastnou náhodou ukončený nulou.)

    Tedy celý rádoby-jednoduchý příklad nikdy, ani jednou neběžel s valgrindem.

    Teď se zbytečně povaluje na webu další totálně rozbitý příklad, který má v C nedefinované chování.

    (A ano, chápu, že předmět dotazu byl úplně jiný.)

    3.9.2020 13:34 Tomas
    Rozbalit Rozbalit vše Re: Využítí pipe v C
    libpipeline. Nemá smysl vymýšlet kolo.

    Založit nové vláknoNahoru

    Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

    ISSN 1214-1267   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.