timed msgrcv()

 ( hofi75 | 2014. március 11., kedd - 22:14 )

Sziasztok,

Van egy készülő program modulom, ami egy child processel ipc message queue-n keresztül kommunikál. Szeretném, ha a fogadó oldali process csak egy adott ideig várakozzon a bejövő adatra, egyébként errno=EINTR-el fejeződjön be a msgrcv() hívás.

Fórumokat olvasva, megpróbáltam az alarm()/msgrcv() kombóval megoldani a dolgot, de valamiért nem működik.

   alarm( timeout);
   if ( msgrcv( msgqid, .......) < 0)
   {
      if ( errno == EINTR) ....
      // error handling
   }

Nos amennyiben lefut a timer, a process-t kilövi a rendszer SIGALRM signal-al. Ha singal handler van definiálva a SIGALRM-re, akkor az még felhívódik és utána hal el a folyamat. Fogalmam sincs, mi lehet a gond. Egyébként a msgrcv() hívás remekül működik, ha van adat a queue-ban.

Teszteltem egy egyszerű alarm küldést és ez gond nélkül megy.

   alarm( 5);
   pause();

Van valakinek tippje, merre induljak? Hogyan tudnék egy timed_msgrcv() jellegű függvényt összekovácsolni?

Üdv,
Gábor

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

Posix IPC nem játszik? Kicsit letisztultabb a dolog. Avagy subs.

Amúgy kis észrevétel: ne <0-t, hanem ==-1-et írj feltételbe, ez jelenti csak a hibás működést.

Köszi, az infót. A programnak több különböző unix platformon (linux, solaris, aix, hp-ux) is futnia kell, most meg kell nézzem, hogy mindenhol elérhető-e a posix ipc.
A relációt ( <0 )javítom. :-)

IPC-re unix domain socket-eket (lasd: `man 2 socketpair`) hasznalne'k, problematol fuggoen stream vagy datagram u"zemmodban. Azokra tudsz select()-tel varakozni, ahol van kulturalt timeout kezeles. Plusz tobb hasonlo blocking jellegu" kommunikaciot ossze tudsz fogni (tobb process es/vagy child kozotti hasonlo jellegu" dolgot, stb). Me'g egy elo"ny hogy ez (is) elfug egy kavefo"zo"n is.

Tudom socketpair()-t úgy használni, hogy a child process nem egy fork() process? Tehát a child nem örökli a socket-eket.

A socketpair() 'unnamed' socketeket gyart, amikre nem lehet kivulrol hivatkozni. Ha neked fuggetlen processzekbol kell tudnod megvalositanod a kommunikaciot, akkor siman socket()/bind()/listen()/accept() fuggvenyeket kell hasznalnod szerver oldalon, kliensen meg socket()/connect() - ugyanugy, mintha TCP/IP-t programoznal, a kulonbseg annyi, hogy AF_UNIX domain lesz a socket, es persze az ipcim helyett is path-t kell megadni. (Amugy unix socketen keresztul nyitott fd-ket is at lehet adni, tehat ugy a socketpair altal krealt azonositokat is tudod fuggetlen helyrol hasznalni - persze ha mar letrehoztad a unix socketeidet, onnantol altalaban felesleges a socketpair() :) )

Hogy e'rted hogy a child nem egy fork()? Ez ellentmond a definicionak :)

így indítom a "child" processt:

   system( "command parms &");

nem akarom a teljes main process-t fork-olni.

Te irod gondolom a "command" binarist is,nem ? Ha igen, akkor miert igy inditod? Nem egyszerubb valoban csak egy mezei fork() ami utana azt a kodreszletet inditja amit egyebkent a `command` csinalna? Pl a command.c-ben csinalsz egy child_main()-t a main() helyett, majd a parent csinal egy fork()-ot es hivja a child_main()-t.

Mindezt azert mondom csak mert (ahogy tobben is emlitettek) ke't random vagy kvazi random (fuggetlen) processz kozotti kommunikaciora a jo unix-os hagyomany az a named socket.

En nem azt tapasztalom, amit te leirtal, ugyanis miutan lefut az (ures) handler, az msgrcv() fuggveny visszaadja az EINTR-t es fut a program tovabb, ahogy kell neki. Ilyesmi problemak debugolasara javaslom a strace-t, azzal eleg jol latszik, ha a syscallok korul valami nem jo.
Viszont el kene gondolkozni, hogy ez-e a megfelelo IPC szamodra. Amennyiben tobb feldolgozo processzed van, amiknek munkat akarsz osztani (vagy tobb helyrol akarsz feladatokat kuldeni), akkor ez a struktura lehet idealis (a tobbi modszer leginkabb pont-pont kapcsolat letrehozasaban segit). Ha tenyleg ilyen busz rendszeru kommunikaciora van szukseged, akkor inkabb az mq_ fuggvenyeket nezd meg (lasd mq_overview) - itt a receive fuggvenynek egybol tudsz timeoutot is adni, nem kell neked koreepitened ennek a kezeleset.
Named pipe-ok is hasonlo szemantikaval kezelhetoek (ott, mivel siman fd-t kapsz, mukodik a select()) - a ket rendszer kozti elterest itt egesz jol leirjak.

Amennyiben a queue NONBLOCK módban lett létrehozva, akkor természetesen EINTR-el lefut, de akkor folyamatosan poll-t kell csinálnom, hogy mikor érkezett adat.

Most nézegetem, hogyan működik a posix mqueue. A kommunikáció a 2 process közt szinkronban fut, tehát parancs-válasz formában. Ami nem világos számomra, hogy egy RDWR módban nyitott mqueue esetén, hogyan tudom elkerülni azt a problémát, hogy P1 process álltal küldött adatot a P2 olvassa ki, ne pedig a P1 saját maga. A sima IPC queue esetén ezt az mtype-al szépen tudom szabályozni, tudom úgymond "címezni" a csomagokat. Ha 2 egyirányú mqueue-t hozok létre, akkor megoldott ez a probléma.
Még azt is ellenőriznem kell, hogy a timed send/recv minden platformon működik-e.

A queue-t en blocking modban csinaltam, var is timeoutig, utana adja nekem az EINTR-t.

Viszont te sima 2 vegpontu kommunikaciot akarsz, kliens-szerver stilusban. Erre nem idealis valasztas semelyik queue sem, inkabb a unix socketek korul nezegess szerintem, az nem ganyolas, hanem pont erre lett kitalalva, mig itt trukkoznod kell hogy azt csinalja amit szeretnel (timeoutok, sajat uzenet visszaolvasasa stb).

sima ipc queue-val (nem posix) sikerült timeout-ot csinálni? hol lehet felparaméterezni? Sehol nem találok erről infót.

Itt a teljes kod (bar elvileg ez is posix/svr4 kompatibilis, man szerint)

Ezért biztosan sokan le fognak hurrogni, de ha *új* programban kell processek/hostok közötti kommunikáció (tiéd mind a küldő, mind a fogadó kód):
http://zeromq.org/

Ha viszont mindenképp alacsony szinten kell fejleszteni:
http://man7.org/linux/man-pages/man7/socket.7.html
http://man7.org/linux/man-pages/man2/setsockopt.2.html
SO_RCVTIMEO and SO_SNDTIMEO
If an input or
output function blocks for this period of time, and data has
been sent or received, the return value of that function will
be the amount of data transferred; if no data has been
transferred and the timeout has been reached then -1 is
returned with errno set to EAGAIN or EWOULDBLOCK, or
EINPROGRESS (for connect(2)) just as if the socket was
specified to be nonblocking. If the timeout is set to zero
(the default) then the operation will never timeout.

zeromq: +1

Időzítésekre a select(2) való. (Vagy pselect, poll, ppoll.)

Szerk: ja, hogy a msg-vel nem megy a select. Akkor ebből socket-et (AF_UNIX, SOCK_DGRAM) kellene fakasztani.

nagyon úgy néz ki hogy az lesz

Én régmúlt fiatalkoromban csináltam egy olyan IPC könyvtárat, ami pont forkolás nélkül szerezte meg a socketpair másik felét.
Volt egy POSIX/SysV message queue-m, és azon keresztül küldözgettem át a file descriptorokat. Nyilván nem volt triviális, illetve gány volt, viszont valamiért (kompatibilitás) nem volt jó a named socket, pipe, whatever. Szórakozásnak, tanulásnak jó volt, másra nem, mert végül nem használtam semmire sem :-).

Mivel alternativ megoldasra kaptal mar eleg javaslatot es kulonben sem ez volt az eredeti kerdes, igy ebbe en most nem megyek bele, viszont erdekelne az a kodreszlet, ahol a signal handler-t regisztralod. Amit itt leirsz ugyanis arra az esetre hasonlit, amikor az SA_RESETHAND flag be van allitva (direkt vagy indirekt, helytelen inicializalas kovetkezmenyekent), ekkor ugyanis a sajat handler hivasa utan az alapertelmezett handler lesz visszaallitva, aminek eredmenyekepp a masodik signalnal a processz "Alarm clock" szoveggel elkoszon. Persze ez csak akkor lehet, ha a fenti kodreszletet egy ciklusban hivod, azaz az elso timeout meg helyesen kezelve lesz, a masodik viszont mar nem. Ha a hiba rogton az elso timeout utan fellep, akkor valami mas van. Irtad, hogy tobb rendszeren futnia kell majd a kodnak, milyen rendszeren probalgatod jelenleg? A fogado oldal kulonben egyszalu, vagy threadek is vannak?

edit:
latva a kodod: lol, na ennyit a fenti teoriarol, nem gondoltam volna, hogy meg van ember aki a signal()-t hasznalja, igaz igy nem is ronthatod el az inicializalast ;)

edit2:
kellene nekem egy szemuveg, az nem is a te kodod rofl :D

Én ilyenkor azt szoktam tanácsolni, hogy rövid, teljes kódot másoljanak be, ami demonstrálja a problémát. De nem szokták megfogadni. :-)

Szívesen bemásolnám a kódot, de annyian javasolták, hogy használjak inkább AF_UNIX socketet, hogy átírtam a kódot, így nincs meg a problémás változat.

Kar. Amikor olvastam, hogy tobb rendszeren is futnia kell a keszulo programodnak, azt hittem valami komolyabb dologrol van szo, de ha megis igy lenne, akkor viszont nem ertem, miert nem vagod be verzio kontroll ala. En ehhez meg a tanulmanyaim alatt hozzaszoktattam magam es az nem ma volt ... Amit meg nem ertek, hogy miert kerulod meg a problemat, ahelyett hogy megkeresned a megoldast? Bar annak van/lehet racionalis oka, hogy pl. socketet hasznalsz az IPC-re, de nem lenne jo tudni, hogy mit csinaltal rosszul, vagy esetleg mit csinal a rendszer(ed) rosszul? Az elobbibol lehet tanulni, az utobbibol meg esetleg lehet bugreportot irni ;)