Homebrew (Wikipedie), správce balíčků pro macOS a od verze 2.0.0 také pro Linux, byl vydán ve verzi 4.5.0. Na stránce Homebrew Formulae lze procházet seznamem balíčků. K dispozici jsou také různé statistiky.
Byl vydán Mozilla Firefox 138.0. Přehled novinek v poznámkách k vydání a poznámkách k vydání pro vývojáře. Řešeny jsou rovněž bezpečnostní chyby. Nový Firefox 138 je již k dispozici také na Flathubu a Snapcraftu.
Šestnáctý ročník ne-konference jOpenSpace se koná 3. – 5. října 2025 v Hotelu Antoň v Telči. Pro účast je potřeba vyplnit registrační formulář. Ne-konference neznamená, že se organizátorům nechce připravovat program, ale naopak dává prostor všem pozvaným, aby si program sami složili z toho nejzajímavějšího, čím se v poslední době zabývají nebo co je oslovilo. Obsah, který vytvářejí všichni účastníci, se skládá z desetiminutových
… více »Richard Stallman přednáší ve středu 7. května od 16:30 na Technické univerzitě v Liberci o vlivu technologií na svobodu. Přednáška je určená jak odborné tak laické veřejnosti.
Jean-Baptiste Mardelle se v příspěvku na blogu rozepsal o novinkám v nejnovější verzi 25.04.0 editoru videa Kdenlive (Wikipedie). Ke stažení také na Flathubu.
TmuxAI (GitHub) je AI asistent pro práci v terminálu. Vyžaduje účet na OpenRouter.
Byla vydána nová verze R14.1.4 desktopového prostředí Trinity Desktop Environment (TDE, fork KDE 3.5, Wikipedie). Přehled novinek i s náhledy v poznámkách k vydání. Podrobný přehled v Changelogu.
Bylo vydáno OpenBSD 7.7. Opět bez písničky.
V Tiraně proběhl letošní Linux App Summit (LAS) (Mastodon). Zatím nesestříhané videozáznamy přednášek jsou k dispozici na YouTube.
Aktuální vývojová verze jádra je 3.14-rc3 vydaná 16. února. Linus začíná být nevrlý: Když jsem psal oznámení rc2, tak jsem zmiňoval jak je malé. Také jsem zmiňoval, jak vám nevěřím a že mám podezření, že se někteří potají smějí a se svými žádostmi o přetažení vyčkávají, zlé malé potvory, jako jste právě vy. A nesnáším, když mám pravdu.
Stabilní aktualizace: verze 3.13.3, 3.12.11, 3.10.30 a 3.4.80 vyšly 13. února. Aktualizace 3.13.4, 3.12.12, 3.10.31 a 3.4.81 se právě revidují; jejich vydání můžeme očekávat 20. února nebo později.
Možná by stálo za to to probrat s lidmi od GCC, abychom přišli na to, jestli nám něco neuniká. (Při méně zjevných hodnotách toho „zjevného“.)
Proč můj strom? Cožpak já spravuji drivers/memory/?
/me hledá v gitu...
Aha, vypadá to, že možná jo...
Ok, jdu to zkouknout.
Pokud nechcete, aby bylo překážkou, že váš zdravý rozum se liší od zdravého rozumu jiných (např. autorů kompilátorů), měli byste usilovat o to, aby specifikace byly přesné a říkaly to, co chcete. Jinými slovy, uvažujte o tom tak, že specifikace je program a lidé jsou počítače; v tomto případě je žádoucí, abyste měli dobře definovaný program.
Zámky souborů jsou intenzivně využívány aplikacemi, jako jsou databázové a souborové servery. Kdykoliv vícero programů přistupuje k souborům současně, je zde riziko poškození dat nebo jiných chyb, pokud přístup není důsledně synchronizován. Zámky souborů tento problém řeší, ale stávající implementace může být obtížné používat, hlavně u vícevlákenných programů. POSIXové zámky specifické pro soubor jsou snahou, jak zkombinovat POSIXové a BSD zámky do podoby API přátelštějšího k používání vláken.
Vícero zapisujících při snaze změnit stejný soubor si může vzájemně rušit své změny. Navíc může být nutné změnu v souboru provést na více místech. Pokud jiné vlákno vidí jen část změn, pak to může vést k vyvolání chyb v programu.
Zámky souborů jsou obecně dostupné ve dvou typech: zámky čtení (také nazývané sdílené) a zápisu (také známé jako výhradní). Pro danou čast souboru je možné vystavit vícero zámků pro čtení, ale zámek pro zápis může být jen jeden, a to jen pokud pro danou oblast není žádný zámek pro čtení nebo zápis. Zatímco na některých operačních systémech jsou zámky povinné, na unixových systémech jsou zpravidla jen jako doporučení (advisory). Takové zámky jsou jako semafory – fungují jen tehdy, když je všichni respektují.
Jeden z hlavních mechanismů pro zamykání souborů je určený standardem POSIX. POSIX nabízí zamykání libovolných rozsahů v souboru pro čtení nebo zápis. Bohužel má ale řadu problémů, kvůli kterým je toto API nevhodné k používání v moderních aplikacích.
Kdykoliv se program pokusí získat zámek, tak je zámek buď přidělen, nebo zamítnut v závislosti na tom, jestli pro daný rozsah už existuje nějaký neslučitelný zámek. Pokud tam žádný neslučitelný zámek není, pak je zámek přidělen. Pokud tam je, pak je zamítnut.
Klasické POSIXové zámky od jednoho procesu nejsou nikdy v konfliktu s jiniými zámky od toho samého procesu. Pokud přijde požadavek na zámek, který by byl v konfliktu s jiným zámkem, jenž ten samý proces předtím vytvořil, pak jádro s požadavkem zachází jako se žádostí o úpravu stávajícího zámku. Proto jsou klasické POSIXové zámky nepoužitelné pro synchronizaci mezi vlákny v rámci stejného procesu. Vzhledem k převaze aplikací používajících vlákna v moderním softwaru jsou POSIXové zámky jako synchronizační mechanismus značně nepoužitelné.
Ještě horší je pak to, že podle standardu jsou všechny zámky zrušeny, pokud proces uzavře kterýkoliv popisovač odpovídající danému souboru, i když tyto zámky byly vytvořeny nad popisovačem, který je stále otevřený. Jde o drobnost, která většinu programátorů překvaví, jelikož si program musí hlídat, aby neuzavřel jakýkoliv popisovač, pokud jsou na příslušném souboru zámky, o něž by se přišlo.
Jestli k tomu může dojít, není lehké určit. Pokud program otevře dva různé pevné odkazy na stejný soubor, vytvoří zámek na jednom popisovači a zavře jiný, pak je tento zámek implicitně zrušen, i když je původní popisovač, kde byl zámek vytvořen, stále otevřený.
Toto je problém především pro aplikace používající složité knihovny pro přístup k souborům. Je běžné mít rutiny, které otevřou soubor, něco přečtou nebo zapíší a pak jej opět uzavřou, aniž by volající aplikace mohla tušit, že k tomu došlo. Pokud aplikace má náhodou na dotčeném souboru zámek, pak o něj může přijít, aniž by o tom věděla. Takové chování může vést k nenápadnému poškozování dat a ztrátě příčetnosti programátora. Jeremy Allison napsal výborný popis tohoto problému a toho, jak takto špatný standard vůbec vznikl (čtěte část nazvanou „First Implementation Past the Post“).
Máme tu ale konkurující (nebo doplňující) standard zamykání souborů, který má své původy v BSD Unixu. Tyto zámky (se kterými se pracuje pomocí volání flock()) mají rozumnější chování. Zatímco POSIXové zámky jsou vlastněné procesem, zámky BSD přísluší otevřenému souboru. Pokud proces otevře soubor dvakrát a pokusí se na obou popisovačích vytvořit výhradní zámek, pak u druhého z nich nebude zámek udělen. Proto se zámky BSD dají používat jako synchronizační mechanismus mezi vlákny, dokud vlákna mají své vlastní popisovače. Pozor na to, že vytvoření klonu popisovače přes dup() nestačí, jelikož je takto vytvořen odkaz na ten samý otevřený soubor.
Navíc jsou zámky BSD uvolněny jen tehdy, když je uzavřen poslední odkaz na otevřený soubor, nad kterým byly zámky vytvořeny. Proto pokud program otevře soubor, vytvoři zámek a následně použije dup() pro naklonování popisovače, tak k uvolnění zámku dojde automaticky až po uzavření obou popisovačů.
Jediným skutečným problémem u zámků BSD je to, že se týkají celého souboru. Oproti tomu POSIXové zámky mohou pracovat s libovolným rozsahem bajtů v souboru. Ačkoliv jsou zámky celých souborů užitečné (a řada aplikací zamyká celé soubory i s POSIXovými zámky), v mnoha případech nestačí. Aplikace jako databáze potřebují detailnější zamykání, aby bylo možné práci lépe paralelizovat.
Dovolím si tvrdit, že to, co potřebujeme, je hybrid těchto dvou zámků – tedy zámek rozsahu bajtů, který má sémantiku zámků BSD při voláních fork() a close(). Navíc protože máme celou řadu programů, které používají „klasické“ POSIXové zámky, tyto nové zámky musejí brát ohled na klasické zámky, aby programy používající nové zámky s nimi dobře spolupracovaly.
Klasické POSIXové zámky se ovládají pomocí několika příkazů předávaných systémovému volání fcntl():
Tyto příkazy jsou doprovázeny ukazatelem na binární argument se struct flock, který vypadá následovně:
struct flock { short int l_type; /* Typ zámku: F_RDLCK, F_WRLCK, or F_UNLCK. */ short int l_whence; /* Vůči čemu je `l_start' relativní (jako `lseek'). */ off_t l_start; /* Offset, na kterém zámek začíná. */ off_t l_len; /* Velikost zamykané oblasit; nula vyjadřuje EOF. */ pid_t l_pid; /* Proces držící zámek. (Jen u F_GETLK) */ };
Stejně tak i POSIXové zámky specifické pro soubor se používají pomocí podobných příkazů, jen mají příponu 'P':
Tyto nové příkazy by měly být těm, kteří používají klasické POSIXové zámky, velmi povědomé a berou ten samý argument struct flock. Jediným rozdílem mezi zámky specifickými pro soubor a klasickými POSIXovými zámky je jejich „vlastnictví“. Klasické POSIXové zámky jsou vlastněny procesem, kdežto POSIXové zámky specifické pro soubor jsou vlastněné otevřeným souborem.
Pro zpřístupnění definic zámků specifických pro soubor je nutné definovat makro _GNU_SOURCE, jelikož tyto zámky ještě nejsou součástí POSIXu. Používání nových zámků se od těch klasických moc neliší. V mnoha případech stačí jen vyměnit hodnotu povelu. Jsou tu ale drobné rozdíly.
Programátor je sváděn k tomu, aby si myslel, že nové zámky jsou „vlastněny“ popisovačem, ale technicky tomu tak není. Pokud je popisovač naklonován pomocí dup(), jádro jednoduše vytvoří dodatečný odkaz na otevřený soubor a přiřadí mu nový slot v tabulce popisovačů. Zámky vytvořené na naklonovaném popisovači nepovedou ke konfliktu k zámkům vytvořeným na původním popisovači. Jádro bude považovat takovou žádost jako požadavek na změnu stávajícího zámku. Navíc zámky specifické pro soubor budou automaticky uvolněny, jen pokud dojde k uzavření obou popisovačů, i když je možné zámek uvolnit ručně pomocí příkazu F_UNLCK.
Chování při fork() je velmi podobné. Při zavolání fork() vytvoří jádro dodatečný odkaz na každý otevřený soubor a přiřadí jej v novém procesu ke stejnému slotu v tabulce popisovačů. Zámky nastavené libovolným z procesů nepovedou ke vzájemným konfliktům a budou automaticky uvolněny, jen když oba procesy popisovač uzavřou.
Klasické zámky a zámky specifické pro soubor budou vzájemně vždy v konfliktu, i když jsou užívány stejným procesem nebo na stejném popisovači. Nepořepokládá se, že by je programy moc míchaly, ale vzhledem k problémům, jaké nedefinovaná chování způsobují, je vhodné to zmínit.
F_GETLK se možná mělo jmenovat F_TESTLK. I když technicky dochází ke vrácení stavu uzamčení určitého rozsahu, jeho pravým účelem je zjistit, zda by daný zámek šlo nastavit, aniž by byl nastaven. Pokud je v daném rozsahu zámek, jenž by byl v konfliktu, pak jádro naplní struct flock informacemi o tomto zámku a nastaví l_pid na číslo procesu, kterému tento zámek patří.
Pole l_pid je pro zámky specifické pro soubor sporné, jelikož tyto zámky nejsou vlastněny procesem. Popisovač mohl být zděděn při fork(), takže hodnota l_pid je u konfliktních zámků poněkud nicněříkající. Přesto je u programů používajících klasické POSIXové zámky nutné do pole l_pid něco dát. Touto hodnotou je -1.
Tento precedens pochází z BSD. Na Linuxu fungují POSIXové a BSD zámky ve zcela odlišném jmenném prostoru. Na BSD ale pracují ve stejném, takže vzájemně vedou ke konfliktům. Pokud program drží zámek BSD na souboru a jiný proces vůči němu udělá F_GETLK, pak jádro BSD nastaví l_pid na -1. Protože přenositelné programy už takovéto chování musejí snášet, tak je používání stejného chování u specifických zámků rozumnou volbou.
U moderních aplikací je běžné, že namísto forku používají vlákna. To je u klasických POSIXových zámků problém. Vztahují se na celý proces, proto nemohou být zámky vytvářené různými vlákny v rámci procesu v konfliktu.
Se zámky specifickými pro soubor je ale možné toto omezení obejít tak, že každému vláknu dáme vlastní otevřený soubor. Zde je příklad (v zájmu jednoduchosti je bez ošetřování chybových návratových hodnot):
#define _GNU_SOURCE #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <fcntl.h> #include <pthread.h> #define FILENAME "/tmp/foo" #define NUM_THREADS 3 #define ITERATIONS 5 void * thread_start(void *arg) { int i, fd, len; long tid = (long)arg; char buf[256]; struct flock lck = { .l_whence = SEEK_SET, .l_start = 0, .l_len = 1, }; fd = open(FILENAME, O_RDWR|O_CREAT, 0666); for (i = 0; i < ITERATIONS; i++) { lck.l_type = F_WRLCK; fcntl(fd, F_SETLKPW, &lck); len = sprintf(buf, "%d: tid=%ld fd=%d\n", i, tid, fd); lseek(fd, 0, SEEK_END); write(fd, buf, len); fsync(fd); lck.l_type = F_UNLCK; fcntl(fd, F_SETLKP, &lck); usleep(1); } pthread_exit(NULL); } int main(int argc, char **argv) { long i; pthread_t threads[NUM_THREADS]; truncate(FILENAME, 0); for (i = 0; i < NUM_THREADS; i++) pthread_create(&threads[i], NULL, thread_start, (void *)i); pthread_exit(NULL); return 0; }
Tato ukázka vytváří tři vlákna, každé z nich pětkrát připíše do souboru. Přístup k souboru je synchronizován pomocí zámků specifických pro soubor. Pokud předchozí program zkompilujeme a spustíme, pak v souboru /tmp/foo bude 15 řádků.
Pokud bychom ale nahradili příkazy F_SETLKP a F_SETLKPW jejich klasickými POSIXovými obdobami, pak by ztratily jakýkoliv účinek, jelikož by byly prováděny tím samým procesem. To vede k poškozování dat (chybějící řádky), jelikož některá vlákna se sejdou a přepíší si data.
Nový typ zámků popisovaný v článku dokáže vyřešit problémy s klasickými POSIXovými zámky, ale programátoři, kteří je chtějí použít, by si měli dávat pozor na odlišnosti.
Vývojáři z několika projektů včetně Samba, NFS Ganesha, SQLite a OpenJDK vyjádřili svůj zájem o používání zámků specifických pro soubor, jelikož pomohou zjednodušit kód ve většině situací a pomohou odstranit problémy s poškozením dat, ke kterému může dojít po zavření souboru.
Podpora pro tento nový typ zámků je dostupná jako patch pro jádro s cílem patch zařadit do Linuxu 3.15. Hodit se může i patch do Glibc doplňující definice nutné pro používání tohoto typu zámků. Dobré je i to, že Austin Group (které dohlíží na POSIX) se myšlenka obecně líbí.
Nástroje: Tisk bez diskuse
Tiskni
Sdílej: