Microsoft zveřejnil na GitHubu zdrojové kódy MS-DOSu 4.0 pod licencí MIT. Ve stejném repozitáři se nacházejí i před lety zveřejněné zdrojové k kódy MS-DOSu 1.25 a 2.0.
Canonical vydal (email, blog, YouTube) Ubuntu 24.04 LTS Noble Numbat. Přehled novinek v poznámkách k vydání a také příspěvcích na blogu: novinky v desktopu a novinky v bezpečnosti. Vydány byly také oficiální deriváty Edubuntu, Kubuntu, Lubuntu, Ubuntu Budgie, Ubuntu Cinnamon, Ubuntu Kylin, Ubuntu MATE, Ubuntu Studio, Ubuntu Unity a Xubuntu. Jedná se o 10. LTS verzi.
Na YouTube je k dispozici videozáznam z včerejšího Czech Open Source Policy Forum 2024.
Fossil (Wikipedie) byl vydán ve verzi 2.24. Jedná se o distribuovaný systém správy verzí propojený se správou chyb, wiki stránek a blogů s integrovaným webovým rozhraním. Vše běží z jednoho jediného spustitelného souboru a uloženo je v SQLite databázi.
Byla vydána nová stabilní verze 6.7 webového prohlížeče Vivaldi (Wikipedie). Postavena je na Chromiu 124. Přehled novinek i s náhledy v příspěvku na blogu. Vypíchnout lze Spořič paměti (Memory Saver) automaticky hibernující karty, které nebyly nějakou dobu používány nebo vylepšené Odběry (Feed Reader).
OpenJS Foundation, oficiální projekt konsorcia Linux Foundation, oznámila vydání verze 22 otevřeného multiplatformního prostředí pro vývoj a běh síťových aplikací napsaných v JavaScriptu Node.js (Wikipedie). V říjnu se verze 22 stane novou aktivní LTS verzí. Podpora je plánována do dubna 2027.
Byla vydána verze 8.2 open source virtualizační platformy Proxmox VE (Proxmox Virtual Environment, Wikipedie) založené na Debianu. Přehled novinek v poznámkách k vydání a v informačním videu. Zdůrazněn je průvodce migrací hostů z VMware ESXi do Proxmoxu.
R (Wikipedie), programovací jazyk a prostředí určené pro statistickou analýzu dat a jejich grafické zobrazení, bylo vydáno ve verzi 4.4.0. Její kódové jméno je Puppy Cup.
IBM kupuje společnost HashiCorp (Terraform, Packer, Vault, Boundary, Consul, Nomad, Waypoint, Vagrant, …) za 6,4 miliardy dolarů, tj. 35 dolarů za akcii.
Byl vydán TrueNAS SCALE 24.04 “Dragonfish”. Přehled novinek této open source storage platformy postavené na Debianu v poznámkách k vydání.
bool Shell::popen3(const string& command, pid_t* pid, Pipes3 pipes)
{
if (!pid) return false;
pid_t cpid;
int p_stdin[2], p_stdout[2], p_stderr[2];
if (pipe(p_stdin) || pipe(p_stdout) || pipe(p_stderr)) goto cleanup;
cpid = fork();
if (cpid < 0) goto cleanup;
if (cpid == 0)
{
//child process
close(p_stdin[P_WRITE]);
dup2(p_stdin[P_READ], STDIN_FILENO);
close(p_stdout[P_READ]);
dup2(p_stdout[P_WRITE], STDOUT_FILENO);
close(p_stderr[P_READ]);
dup2(p_stderr[P_WRITE], STDERR_FILENO);
execl("/bin/sh", "sh", "-c", command.c_str(), NULL);
exit(-1);
}
*pid = cpid;
pipes[P_IN] = fdopen(p_stdin[P_WRITE], "w");
pipes[P_OUT] = fdopen(p_stdout[P_READ], "r");
pipes[P_ERR] = fdopen(p_stderr[P_READ], "r");
return true;
cleanup:
close(p_stdin[P_READ]); close(p_stdin[P_WRITE]);
close(p_stdout[P_READ]); close(p_stdout[P_WRITE]);
close(p_stderr[P_READ]); close(p_stderr[P_WRITE]);
return false;
}
Celá funkce pracuje celkom dobře, akorát je problém s ukončením child processu.Řešení dotazu:
Po zavolání téhle funkce čtu stdin/stderr výstup child programu a nějak ho zpracovávám.
Můj (rodičovský) proces se tak zasekne na volání fgets/fgetc apod.Tohle čtete jak? Správně to musíte číst oboje najednou, tj. přes select() ... ideálně, pokud budete chtít i zapisovat, tak musíte selectovat všechny 3 roury, jinak může dojít k deadlocku mezi libovolnýma dvěma: např. Vy čekáte na výstup potomka a ten čeká na vstup od Vás, nebo potomek chce zapisovat do stderr, ale ten blokuje, protože má plný buffer, protože nečtete rouru stderr, protože jste zablokován čtením roury stdout. Všechny tyto problémy řeší zmíněný select(). Ad ukončení procesu potomka: Pokud potomek skončí (i neočekávaně), dostanete při čtení EOF (pokud se opravdu pokoušíte číst a nejste v deadlocku, viz výše) a při zápisu EPIPE (a signál SIGPIPE, který standardně Váš proces zabije, takže je vhodné to mít ošetřené). Ad zombie: Když potomek skončí, přejde do stavu zombie automaticky a zůstane v něm dokud si nevyzvednete jeho exit status pomocí nějakého volání z rodiny wait(). Při skončení potomka dostanete taky signál SIGCHLD, abyste věděl, že si máte status vyzvednout, záleží pak na logice Vaší aplikace, jestli to udělá hned, nebo v rámci např. čtecího cyklu. Management procesů je obecně netriviální záležitost. To ještě neřešíte např. ukončení potomků potomka (/bin/sh pouští další procesy), případně korektní ukončení (zabití) potomků, pokud se Vaše aplikace rozhodne skončit/spadne...
select()
a zkusil implementovat, ale chová se to teď nějak úplně divně.
timeout.tv_sec = 5;
timeout.tv_usec = 0;
bool go_on = true;
while (go_on)
{
FD_ZERO(&set_r);
FD_SET(fileno(pipes[P_OUT]), &set_r);
nfds = max(nfds, fileno(pipes[P_OUT]));
FD_SET(fileno(pipes[P_ERR]), &set_r);
nfds = max(nfds, fileno(pipes[P_ERR]));
timeout.tv_sec = 1;
timeout.tv_usec = 0;
cout << "select: " << (success = select(nfds, &set_r, NULL, NULL, &timeout)) << "\n";
if (success == -1) return false;
go_on = false;
while (FD_ISSET(fileno(pipes[P_OUT]), &set_r))
{
fgets(buffer_r, BUF_LEN, pipes[P_OUT]);
out << "[stdout] " << buffer_r;
go_on = true;
}
if (FD_ISSET(fileno(pipes[P_ERR]), &set_r))
{
fgets(buffer_r, BUF_LEN, pipes[P_ERR]);
out << "[stderr] " << buffer_r << "\n";
go_on = true;
}
}
Tento kód vypíše pouze první řádku výstupu child procesu, potom už select()
jen nulu,
ačkoli když přesto čtu stdin, jsou tam znaky k přečtení.
(Stdin zatím neuvažuju, dokud nerozchodím alespoň stdout a stderr.)
Srovnejte si select(2) a pselect(2), pokud chcete řešit souběh s nastavováním obsluh signálů.
Mimochodem timeout můžete nechat na nekončnu, protože příchodem signálu bude volání přerušeno a select() vrátí -1 a errno bude EINTR.
Já signály vůbec nezpracovávám
se už žádný signál neodešle
Tak jde o signály, nebo ne?
Když chcípne potomek, tak čtecí konec roury vrací EOF, na což samozřejmě select() zareaguje tím, že v množině čtecích deskriptorů se objeví připravený deskriptor, ze kterého read() vrátí 0.
Select při čtení z ukončeného procesu označí fd jako že z něj de číst, ale při čtení dostanete přečteno 0 bajtů = EOF.Mně se select() po skončení child procesu zasekne, pokud *timeout == NULL. Mám ověřené, že to je právě volání select(), na kterém se to zarazí.
Signál CHLD Vám přijde pokud ho neignorujete (nastavíte si handler).Je nějaký zásadní důvod, proč bych to měl dělat? Polling afaik ničemu nevadí. CPU nevytěžuje.
Mně se select() po skončení child procesu zasekne, pokud *timeout == NULL. Mám ověřené, že to je právě volání select(), na kterém se to zarazí.To je asi tím že neselectujete chybové stavy (třetí fdset).
Je nějaký zásadní důvod, proč bych to měl dělat? Polling afaik ničemu nevadí. CPU nevytěžuje.Maskujete si tím chybové chování.
To je asi tím že neselectujete chybové stavy (třetí fdset).Zkusil jsem do
exceptfds
dát stind a stdout pajpy, ale select()
se při *timeout = NULL
stále zasekává.exceptfds
jinak? Z man select
to není úplně zřejmý...Maskujete si tím chybové chování.Sledovat, jestli
select()
nevrací -1 nestačí?
exceptfds
taky sleduju pro případný errory... no tak snad už to je plně košér
takže selectem neodlišim stav, kdy child potřebuje něco čístJelikož jsou mezitím různé buffery a potenciálně nemusí být příjemce ani na stejném stroji, tak to opravdu nepoznáte. Ale nedovedu si představit situaci kde byste něco takového využil. Normální duplexní protokoly fungují na principu požadavek a odpověď.
exceptfds taky sleduju pro případný errory... no tak snad už to je plně košérKdyž tak pro jistotu ještě ukažte jednou ten kód. Nezdá se mi, že by měl druhý fdset nějaký vliv na funkci prvního a třetího.
Když tak pro jistotu ještě ukažte jednou ten kód. Nezdá se mi, že by měl druhý fdset nějaký vliv na funkci prvního a třetího.Ok, ale upozorňuju, že ten kód je stále dost neučesanej, možná tam jsou proměnný navíc, instream(stdin) vyhodim, musim dodělat error handling při otevřených pajpách, ...atd.
bool Shell::issue(const string& command, ostream& out, istream& in, int* retvalue, bool* normal_exit)
{
if (!retvalue) return false; //ep_nodep
if (!normal_exit) return false;
if (command.empty()) return false;
Pipes3 pipes;
pid_t pid, w;
fd_set set_r, set_w, set_err;
int nfds = 0;
struct timeval timeout;
int success;
char buffer_r[BUF_LEN];
string buffer_w;
int bytes;
int child_status;
string prefix = command.substr(0, command.find_first_of(' '));
stringstream ss;
if (!popen3(command, &pid, pipes)) return false;
// interrogate child process output/(input)
bool go_on = true;
while (go_on)
{
FD_ZERO(&set_r);
FD_SET(pipes[P_OUT], &set_r);
nfds = max(nfds, pipes[P_OUT]);
FD_SET(pipes[P_ERR], &set_r);
nfds = max(nfds, pipes[P_ERR]);
FD_ZERO(&set_w);
FD_SET(pipes[P_IN], &set_w);
nfds = max(nfds, pipes[P_IN]);
FD_ZERO(&set_err);
FD_SET(pipes[P_OUT], &set_err);
FD_SET(pipes[P_ERR], &set_err);
timeout.tv_sec = 0;
timeout.tv_usec = 10000;
if(select(nfds+1, &set_r, &set_w, &set_err, /*&timeout*/NULL) == -1 ) /* TODO: error */;
if (FD_ISSET(pipes[P_OUT], &set_err)) /*error*/;
if (FD_ISSET(pipes[P_ERR], &set_err)) /*error*/;
//if (FD_ISSET(pipes[P_IN], &set_w)) /*always*/;
if (FD_ISSET(pipes[P_OUT], &set_r))
{
bytes = read(pipes[P_OUT], buffer_r, BUF_LEN);
buffer_r[bytes] = '\0';
ss << buffer_r;
while (ss.good())
{
ss.getline(buffer_r, BUF_LEN);
if ((ss.gcount() > 0) && (strlen(buffer_r) > 0)) out << " [" << prefix << "] " << buffer_r << "\n";
}
ss.clear(); /* TODO: jeste nejak vyprazdnit stringstream*/
}
if (FD_ISSET(pipes[P_ERR], &set_r))
{
bytes = read(pipes[P_ERR], buffer_r, BUF_LEN);
buffer_r[bytes] = '\0';
ss << buffer_r;
while (ss.good())
{
ss.getline(buffer_r, BUF_LEN);
if ((ss.gcount() > 0) && (strlen(buffer_r) > 0)) out << " [" << prefix << "] " << buffer_r << "\n";
}
ss.clear();
}
/*if (FD_ISSET(fileno(pipes[P_IN]), &set_w))
{
/// TODO: oddelat stdin
}*/
w = waitpid(pid, &child_status, WNOHANG|WUNTRACED|WCONTINUED);
if (w == -1)
{
//TODO: error handling
go_on = false;
} else if (w != 0)
{
if (WIFEXITED(child_status))
{
*retvalue = WEXITSTATUS(child_status);
*normal_exit = true;
go_on = false;
} else if (WIFSIGNALED(child_status))
{
*retvalue = WTERMSIG(child_status);
*normal_exit = false;
go_on = false;
}
}
}
pclose3(pipes);
return true;
}
Nejspíš budu taky moct přehodit celou waitpid část až za smyčku, páč timeout může nyní být nekonečný.
/*error*/
, protože ignorování chyby může být zdroj potíží úplně jinde. Když jsme u toho, vidím, že se snažíte o C++, tak co třeba zkusit občas něco throw
nout?
Nejspíš budu taky moct přehodit celou waitpid část až za smyčku, páč timeout může nyní být nekonečný.Z principu věci by to mělo být až za smyčkou, protože smyčka by měla skončit až skončí proces (nebo při chybě). Podobně tak je možno naplnit všechny fdsety coby vzor před smyčkou a uvnitř smyčky inicializovat pracovní fdsety pomocí memcpy (select je zmodifikuje, takže inicializaci se nevyhnete, jen je to takto rychlejší). Poslední věc co by asi stála za zvážení je odsunout něco do separátních podprogramů, na mě je tam už moc lokálních proměnných.
Na error kontrolujte i P_IN.Ok, na to jsem zapomněl...
Když jsme u toho, vidím, že se snažíte o C++, tak co třeba zkusit občas něco thrownout?Hm, to bych případně mohl taky. Na jiných místech programu exceptions používám, takže proč ne... ještě ten error handling nějak vymyslim a zvážím to.
Podobně tak je možno naplnit všechny fdsety coby vzor před smyčkou a uvnitř smyčky inicializovat pracovní fdsety pomocí memcpy (select je zmodifikuje, takže inicializaci se nevyhnete, jen je to takto rychlejší).Jj, měl jsem tam dřív něco jako tmp_set_r a další, ale oddělal jsem je, protože jsem při hledání chyb podezříval kde co. Zas to dám zpátky.
Poslední věc co by asi stála za zvážení je odsunout něco do separátních podprogramů, na mě je tam už moc lokálních proměnných.Tjn, je toho tam trochu moc, taky už mi to vadí. Nějak to časem pořešim.
Popravdě řečeno by se mi asi nejvíc líbilo řešení, kdy funkce by vracely nějakou malou "úspěchovou" třídu,Smysl výjimek je v tom, že nemusíte vracet nic (a obvykle to co říkáte je pokryto více typy výjimek). Kód pak není přecpán if-y a navíc se obrací logika ignorace chyby - pokud s ní nic neuděláte tak program skončí, verzus pokud ignorujete návratovou hodnotu, tak se nestane nic.
Mít tak víc volnýho času, věčný to problém...Ten mám taky. Proto se snažím dokumentovat a psát pořádně hned od prvního řádku, abych pak po půl roce neměl chuť se za ten bordel nakopat do zadku.
Chtěl jsem tim říct, že obcházíte něco, co "nefunguje" jak by mělo.Maskujete si tím chybové chování.Sledovat, jestli select() nevrací -1 nestačí?
Tiskni Sdílej: