Blogowa przeprowadzka

Dynamiczny rozwój mojej firmy Iterators, o której pisałem jakiś czas temu wymusił na mnie bardziej pieczołowite dbanie o swój wizerunek, modnie mówiąc personal brand. Z tego też powodu, aby dotrzeć do większej liczby czytelników, blog będzie wkrótce znajdował się pod nowym adresem http://luksow.com i co prawdopodobnie ważniejsze – będzie prowadzony w całości po angielsku. Mam nadzieję, że przez te 6 lat blogowania moi czytelnicy zdążyli się już nauczyć „uniwersalnego języka informatyki”. Jeśli nie, to cóż…zostały na to jeszcze dwa – trzy tygodnie :)

Instrukcja migracji

Migracja do nowego adresu będzie dla czytelników całkowicie bezbolesna – nie musicie nic robić.

Adres http://lukaszsowa.pl będzie przekierowywał na http://luksow.com, RSS będzie dalej działał, bo używam FeedBurnera, stary blog i posty będą dostępne pod http://archiwum.lukaszsowa.pl, natomiast wszystkie istniejące linki do postów będą dalej działały jak powinny.

Treść

Treść nowego bloga mam nadzieję będzie znacznie ciekawsza od moich ostatnich wypocin, które zapewne zanudziły nawet „najbardziej zagorzałych fanów”. Będzie (prawie?) tylko technicznie i biznesowo. Jednym słowem – soczyście.

A więc – do usłyszenia już wkrótce na nowym-starym blogu!

PS. W komentarzach wpisujcie miasta!

Oto Iterators!

W poprzednim poście obiecywałem zaprezentować mój najnowszy projekt informatyczny. Nie jest to jednak zwykły kawałek kodu zamieszczony na GitHubie, a realizacja mojego największego marzenia zawodowego – własna firma o nazwie Iterators.

Mówiąc najkrócej Iterators to software house, który zajmuje się wszelkiego rodzaju rozwiązaniami software’owymi – w szczególności webowymi, mobilnymi i przetwarzaniem danych. Naszymi klientami są przede wszystkim startupy, mały i średni biznes, agencje marketingowe i w mniejszym stopniu korporacyjny świat IT. Technologicznie rzecz ujmując… cóż wykorzystujemy najlepsze narzędzia do rozwiązywanych problemów – nie jesteśmy tylko programistami .NET czy Ruby – lubię określenie „poligloci”. Pełne informacje na temat naszych usług można odnaleźć na podstronie Services.

Kończąc wywód czysto marketingowy napiszę nieco o samym pomyśle. Zaczynając studia myślałem, że zostanę obiecującym, korporacyjnym programistą .NET. Niestety wypadło tak, że wiek buntu zaczął mi się dopiero w połowie studiów i od tej pory w zasadzie myślałem już tylko o własnym biznesie. Kocham programować, więc jasne było dla mnie to, czym chciałbym się zajmować. Jednak robienie tego „dla kogoś” wydaje mi się suboptymalne. Patrząc na osoby, które wybrały pracę w stabilnych firmach widzę jak mały wpływ mają na kierunek rozwoju tego co robią, na sposoby pracy i generalnie na to co się wokół nich dzieje. Mi to się zdecydowanie nie podoba. Chcę spróbować robić „po swojemu”.

Wiele osób mówi, że własny biznes zaraz po studiach to głupi pomysł. Uważam jednak, że w moim przypadku jest zupełnie inaczej. Przede wszystkim w tej chwili nie pociąga to za sobą żadnego ryzyka. Nie mam rodziny na utrzymaniu, mam dach nad głową i mam wystarczające oszczędności. Co mogę stracić? Nic. W najgorszym wypadku zostanę z kilkoma miesiącami ciekawych doświadczeń i miłego życia wypełnionego realizacją marzeń. Doświadczenie? Nie lubię się chwalić, ale ze swojego jestem zadowolony i mam nadzieję, że mi ono wystarczy. Nie potrzebuję styczności z miernym middle-managmentem, żeby wiedzieć jak radzić sobie w życiu (a to właśnie wielu nazywa „cennym doświadczeniem”). Dlaczego zatem nie spróbować?

Co teraz? Jest konkretny plan i zamierzam go konsekwentnie realizować. Jeśli wypali, to chętnie podzielę się tutaj tym jak wygląda własny biznes „od środka”.

PS. Jeśli potrzebujesz oprogramowania najwyżej jakości pomyśl o zatrudnieniu Iteratorów! :)

Koniec… i początek

Kolejny niechlubny rekord został pobity – blog nie był aktualizowany przez blisko rok. Wydarzyło się w tym czasie (licząc jednostkowo) całkiem niedużo, mianowicie 25 czerwca 2013 roku udało mi się ukończyć ukochane przeze mnie studia. Jest to dla mnie jednak całkiem wyjątkowe zdarzenie. Od lipca czuję się wolnym człowiekiem – moich myśli nie zaprzątają bzdury związane z pracą dyplomową czy rejestracją na nowy semestr. W końcu tak naprawdę zacząłem zajmować się rzeczami, które lubię i o których marzyłem i robię to w sposób całkowicie nieskrępowany. Znajomi? Zawsze chętnie! Spotkania branżowe? Staram się nie odpuszczać (o ile PKP mnie nie pokonuje :)). Piłka nożna? Oglądam bez wyrzutów sumienia! Gra na gitarze? W końcu próbuję coś brzdąkać. Programowanie naprawdę użytecznych i fanych rzeczy? O taaaak.

Wnikliwy czytelnik zapewne pomyśli: „opier…asz się brachu, a co z pracą?”. Ano pracuję i to nad bardzo ciekawym doświadczeniem informatycznym, o którym szerzej już w następnej notce, która powstanie w ciągu kilku dni.

Na sam koniec pozostaje kwestia bloga. Bardzo chcę blogować i mam po prostu nadzieję, że teraz to się uda. Mam bardzo dużo zaległych postów, które nazwałbym retrospekcyjnymi, bo dotyczą wydarzeń z przeszłości. Mogą się okazać one mało interesujące dla większości czytelników, ale bardzo ich potrzebuję, żeby mieć gdzieś zanotowane przemyślenia na temat spraw ważnych dla mnie. Po kilku (w porywach do 8!) notkach osobistych wrócę do czystej technologii. Oby się udało!

Na zakończenie dziękuję wszystkim, którzy sprzątając po Google Readerze nie usunęli mojego bloga ze swojego czytnika :).

Przedostatni semestr studiów

Post jest częścią serii retrospekcja (patrz tutaj), która służy mi do uwiecznienia wydarzeń, które miały miejsce w przeszłości. Notki te mogą okazać się mało interesujące dla Czytelnika, ale obiecuję, że po zakończeniu serii nastąpią soczyste, techniczne wywody.

Nihil novi sub sole

Studia magisterskie nie zaczęły się zbyt dobrze. Semestr drugi i zarazem przedostatni tej całej męczarni również nie rozpieszczał. Założenie na ten czas było jednak proste – zrobić wszystkie przedmioty tak, aby na ostatni semestr została już tylko praca magisterska.

Chcąc nie chcąc program studiów ponownie zmusił mnie do wzięcia przedmiotów dotyczących uczenia maszynowego… i tym razem całkiem się to opłacało. Rozpoznawanie obrazów i metody odkrywania wiedzy to dwa przedmioty o niezbyt zrozumiałych nazwach, które doskonale uporządkowały wiedzę, którą z trudem zdobywałem na semestrze pierwszym. Oczywiście nie obyło się bez bombardowania mojej biednej głowy matematycznymi formułami, dowodami i wywodami, ale tak po prawdzie to da się to wszystko zrozumieć „na chłopski” rozum – intuicyjnie znaczy się. Podsumowując zyski i straty te dwa przedmioty zaliczyłbym na plus – może niezbyt wyraźny i pewny, ale jednak plus.

Dalej było niestety sporo gorzej. Z przedmiotem o pięknej nazwie programowanie równoległe i rozproszone wiązałem spore nadzieje, ponieważ tematy współbieżności, równoległości i wszelkiego rozproszenia są mi bliskie i bardzo je lubię. Niestety srogo się zawiodłem, ponieważ przedmiot ten tylko w nazwie jest fajny. Dalej są już prowadzący, którzy ograniczają się do czytania slajdów na temat przestarzałych technologii, ewentualnie takich, których nikt nigdy nie widział. Nastawiałem się na „grube rozkminy” na tematy typu CSP vs. model aktorów, a otrzymałem siekę na temat ewolucji procesorów, europejskich klastrów i różnic w wątkach pthreads i javowych. WTF? Prowadzący zawiedli. Na całej linii, ech.

Pomimo kiepskiej opinii zmusiłem się do wzięcia przedmiotu o (znów) ładnej nazwie – analiza i projektowanie systemów informatycznych. Bo dużo ECTS-ów za to dawali. To był błąd, zdecydowanie największy błąd podczas toku studiowania, wyłączając oczywiście wybór wydziału :P. Wykład tego przedmiotu ma dwa oblicza – ciekawe, dotyczące agile i scruma (1/3 całości) oraz fatalnie beznadziejne – dotyczące metod „łoterfalowych” – przypadki użycia i rysowanie diagramów UML na potęgę (a propos tego ścierwa to polecam spojrzeć tu). To jeszcze byłoby do łyknięcia, gdyby nie projekt. Projekt polega na stworzeniu małego produktu zwinnymi metodykami, gdzie każdy w teamie po kolei realizuje inną rolę z zespołu scrumowego^C^C^C^C To oczywiście tylko moja fantazja, tak naprawdę projekt polega na napisaniu dokumentacji do pewnego produktu, najlepiej takiej, która ma 100+ stron, w zasadzie im więcej tym lepiej. I diagramy, dużo diagramów. Inteligentny sposób spędzania czasu, nie ma co, naprawdę. Co ciekawe, to jeszcze nie byłoby najgorsze, gdyby nie to, że do projektu trafiła mi się najbardziej stępiona dzida wydziału, którego imienia nie pomnę. Chamstwo, niekompetencja, niesprawiedliwość. Tak opisałbym metody prowadzenia zajęć przez tego człowieka. Ech, starczy tego używania sobie – po prostu było źle, naprawdę bardzo źle.

Praca magisterska

Semestr drugi poświęciłem na wymyślaniu i badaniu potencjalnego tematu pracy magisterskiej. To przysporzyło mi sporo stresów ponieważ wymyśliłem sobie (no dobra, niezupełnie sam), że chciałbym napisać co nieco o połączeniu współbieżności i bezpieczeństwa, co w praktyce okazało się cholernie trudne. Przez cały semestr czytałem „pejpersy” na temat błędów, niezawodności, bezpieczeństwa i samej współbieżności. Samej pracy nie powstał natomiast ani jeden akapit. Co z tego wyszło? O tym dokładniej niebawem.

Studia magisterskie…i co z tym blogiem?

Tak długiej przerwie w pisaniu na blogu chyba jeszcze nie miałem – nie udało się nic napisać w semestrze ani w czasie wakacji, nawet tradycyjny wpis o szkole się wymknął… Cóż, winnego daleko szukać nie będę, bo jestem nim ja. Taki stan rzeczy wcale mi się nie podoba, a wprost przeciwnie – powoduje wyrzuty sumienia i poczucie zmarnowanego potencjału… Czemu więc?

Brodzenie po kolana w g…

Uczciwie zastanowiłem się nad tą kwestią i odpowiedź jest bardzo prozaiczna. Żeby pisać na blogu trzeba to lubić, trzeba mieć o czym pisać, trzeba czuć entuzjazm do tematów, które się porusza… i to tyle. Bywały chwile, w których nie miałem z tym problemu jak choćby spora liczba wpisów o dotnecie czy też seria o osdevie. Oba tematy w tamtych czasach były mi bliskie, elektryzowały mnie na swój sposób – chętnie dzieliłem się nabytą wiedzą i nie miałem z tym problemów. Wspomniane przypadki łącz też jeszcze jedna rzecz – szczyt ich rozwoju przypadał na okres kiedy nie musiałem chodzić do szkoły.

Miniony, pierwszy semestr studiów magisterskich bardzo dotkliwie przypomniał mi jak studia przyczyniają się do mojego wypalenia. Ciężko odnaleźć w sobie entuzjazm i chęć do zajmowania się czymkolwiek jeśli kilka godzin spędza się na uczelni walcząc z jakimś „inżynierskim oprogramowaniem wysokiej klasy”, którego główną funkcjonalnością jest wyświetlania okienka z napisem Exception in thread „main” java.lang.NullPointerException, prawie dwie godziny na podróży do i z uczelni, wieczór na robieniu projektów, a noc na przygotowaniach do kolokwium. Studia magisterskie to nic więcej, jak tylko nieudana powtórka ze studiów inżynierskich – nieudana, bo jeszcze bardziej bez pomysłu. Przez ostatnie dwa miesiące widziałem wszystkie wschody słońca i wcale nie dlatego, że jestem taki romantyczny… Po prostu zajmowałem się bezmyślnym przetwarzaniem programów „inżynierskich”, formułek pseudomatematycznych, algorytmów których zastosowania jeszcze nikt nie odkrył i całej maści innego gówna. Osoba wymyślająca plan studiów powinna za karę resztę swojego życia spędzić na programowaniu w Javie, publicznie na rynku Starego Miasta… (resztę tej perwersyjnej fantazji bez opisu). Czy naprawdę ostatnim nierozwiązanym problemem informatyki jest to jak sklasyfikować wszystko za pomocą jakże porywających klasyfikatorów? Czy umiejętność odtworzenia algorytmu przekształcania automatu niedeterministycznego do deterministycznego naprawdę się może do czegoś przydać? Czy problemy grafowe ograniczają się do DFS-a i BFS-a? Retorycznych pytań tego typu mógłbym zadać jeszcze wiele… ale po co się denerwować? Wrzucanie wszystkich przedmiotów do jednego worka podpisanego „tragicznie złe” byłoby oczywiście niesprawiedliwe, bo w tym bagnie znalazłoby się po jednym przedmiocie z grupy „znośny”, „przeciętny” i „całkiem dobry”, ale niestety giną one w grubej warstwie gnoju.

Co dalej?

Są ludzie, nawet całkiem dużo, którzy lepiej radzą sobie ze studiami. Lepiej, to znaczy mniej się nimi interesują. Nie denerwuje ich niski poziom wykładów – po prostu na nie nie przychodzą. Nie starają się znaleźć wartości dodanej – uczą się w ostatniej chwili z gotowców. W końcu – nie zależy im na wynikach i mają dzięki temu lżejsze i pewnie ciekawsze życie. Mi to się niestety nie udaje. Mam głęboko zakorzenioną sumienność i jeśli już za coś się zabrałem (a tak właśnie zrobiłem) chcę to skończyć możliwie jak najlepiej.

Dobra wieść jest taka, że to jeszcze tylko bieżący i następny semestr i już koniec. Definitywnie. Na całe szczęście semestry te są maksymalnie odciążone, więc będę miał nieco więcej czasu dla siebie i oczywiście dla pracy magisterskiej. Kolejna praca dyplomowa to zdecydowanie najjaśniejszy punkt na tym zachmurzonym niebie studiów – to po prostu dobra zabawa i wielka satysfakcja z odkrywania czegoś nowego. Mam nadzieję, że uda mi się odnieść sukces co najmniej dorównujący pracy inżynierskiej. Co po studiach? Mam nadzieję, że uda mi się pokierować swoją karierą tak jak ja tego chce i nie dam się wkręcić w robienie czegoś czego nie chce tak jak ma to miejsce na studiach. Wtedy tematy na bloga na pewno pojawią się same, a wraz z nimi chęci :)

Ok, koniec już narzekania. Następny post mam nadzieję przed lutym!

Emacs w wydaniu dla twardzieli

Na przestrzeni czasu zaprzyjaźniłem się ze świetnym edytorem jakim jest Emacs. Nasza długotrwała relacja spowodowała, że postanowiłem przenieść ten związek na wyższy poziom.. i udało się, jest jeszcze lepiej :). Teraz rozstajemy się jeszcze rzadziej. Jeśli Drogi Czytelniku też masz ochotę na głębszy romans, zapraszam do lektury tego wpisu.

Destrukcja

Podobno czasem bywa, że aby coś zbudować, trzeba coś zniszczyć. Tak zrobimy i tym razem i tworzenie  nowego, lepszego świata zaczniemy od… usunięcia Emacsa i wszystkiego co z nim związane z systemu. Większość osób instaluje edytor z dystrybucyjnego repozytorium. Takie rozwiązanie jest wygodne, ale ma kilka przykrych konsekwencji. Przede wszystkim repozytoria często zawierają nieaktualne wersje, a wbrew pozorom Emacs rozwija się całkiem szybko, więc łatwo pozostać w tyle. Drugą sprawą są zależności, które instalują się przy okazji – nie zawsze wiadomo co to jest. Różne dystrybucje wykorzystują różne rodzaje repozytoriów, a więc ewentualne przeniesienie naszego środowiska pomiędzy dystrybucjami może sprawić niepotrzebny kłopot. Odpowiedzią na te problemy jest kompilacja – proces sporo trudniejszy, no ale coś za coś. W każdym razie pacman -R (czy co tam kto używa) do rąk i do dzieła! Ważne, aby wszystko usunąć – nie tylko podstawowy edytor, ale również wszystkie pakiety wspomagające – dodatkowe mody itd.

Budowanie

Po słodkim zniszczeniu pora zacząć budowanie nowego świata. Pierwszym krokiem będzie sklonowanie najnowszej wersji z repozytorium:

git clone git://git.savannah.gnu.org/emacs.git

a następnie kompilacja i instalacja:

./autogen.sh
./configure
make
sudo make install

i gotowe! Nasz nowy, błyszczący Emacs jest gotowy. W przypadku gdybyśmy chcieli zaktualizować naszą kompilację należy wyczyścić stare efekty, pobrać zmiany i powtórzyć cały proces:

make clean
git pull
./autogen.sh
./configure
make
sudo make install

Prace wykończeniowe

Nie od dziś wiadomo, że to prace wykończeniowe zajmują najwięcej zasobów – tak też jest w tym wypadku.

Dodatki

„Goły” Emacs, mimo że bardzo rozbudowany, nie posiada wszystkiego, co potrzebne do szczęścia. Z tego powodu na pewno chcielibyśmy wyposażyć naszą kompilację w szereg dodatków. Wszystkie dodatkowe moduły warto trzymać uporządkowane, w jednym miejscu. W ten sposób przeniesienie ich na inny system będzie wymagało zaledwie skopiowania pojedynczego katalogu. Genialne w swej prostocie, prawda? Osobiście preferuję przechowywanie dodatków w katalogu ~/.emacs.d, w którym utworzyłem sobie dwa katalogi: modules i themes, które odpowiednio zawierają moduły i motywy graficzne.

Konfiguracja

Skonfigurowanie Emacsa, skrojone do indywidualnych potrzeb jest zadaniem dosyć skomplikowanym. Zajmę się tym w kolejnej notce z serii emacsowej. Na chwilę obecną proponuję obejrzeć mój plik konfiguracyjny, który jest dosyć obszernie skomentowany.

Uruchamianie

Gdy mamy już wszystko elegancko skonfigurowane można swobodnie zacząć używać Emacsa, ale… wpisanie w konsoli „emacs” jest passe, demode i w ogóle bleee. Osobiście, w trakcie uruchamiania systemu odpalam Emacsa w trybie daemona:

emacs --daemon

Wtedy Emacs będzie pracował zawsze w tle, a jego uruchomienie za pomocą polecenia:

emacsclient

będzie się odbywało niemal natychmiastowo. Istotną zaletą takiego podejścia jest ciągłe przechowywanie sesji no i wysoka efektywność i wygoda. Wadą natomiast może być konieczność rozsądnego zarządzania buforami, które nie zamykają się same. W tym miejscu warto również stworzyć dla powyższego polecenia wygodny alias – w moim wypadku jest to po prostu e. e nazwa_pliku uruchamia mi ramkę Emacsa z plikiem gotowym do edycji i jest to co najmniej tak wygodne jak vim ;>.

Na zakończenie

Używanie Emacsa w ten sposób jest bardzo wygodne i już wiem, że nie zamienię go na nic innego :). Serdecznie polecam wszystkim spróbowanie takiego podejścia. Niedoświadczonym proponuję sklonowanie sobie mojego repozytorium z dotfiles:

git clone git://github.com/luksow/dotfiles.git

Można tam znaleźć mój katalog .emacs.d, plik konfiguracyjny Emacsa .emacs oraz plik .bash_rc z ustawieniami aliasów.

Powodzenia!

Praca inżynierska – epilog

Blog nosi znamiona pamiętnika, zatem wpis ten powstaje ku pamięci, aby zachować historię powstawania moje pracy inżynierskiej. Tym samym skończę tematykę moich studiów inżynierskich, która pewnie dla niewielu osób jest interesująca.

Część praktyczna…

O szczegółach trudnych początków można było przeczytać wcześniej. W czasie wakacji skoncentrowałem się na tworzeniu praktycznej części pracy. Podczas analizy systemu Google Chrome OS napotkałem na pewien nierozwiązany problem. W Linuksie brakuje mechanizmu, który pozwalałby na ograniczenie dostępnego zbioru wywołań systemowych. Tego typu narzędzie pozwala na działanie w myśl zasady najmniejszego uprzywilejowania i powstrzymywanie ataków ze wstrzykiwaniem kodu. Istniejące rozwiązania są niewystarczające – posiadają zbyt małe możliwości, są niewydajne lub niebezpieczne. Z tego powodu ochoczo zabrałem się za stworzenie rozwiązania, które może sprostać oczekiwaniom projektu Chrome OS i pozostałej części społeczności :).

W związku z powyższym stworzyłem moduł, który pozwala pogrupować zadania w grupach kontrolnych, a następnie zdefiniować dostępny dla nich zbiór wywołań systemowych. Tym samym można zabronić procesom np. otwierania i tworzenia plików, zmieniania uprawnień, forkowania itd. Na uwagę zasługuje wydajność rozwiązania. Użycie modułu spowalnia zadania o nie więcej niż 5%, co jest zdecydowanie dobrym wynikiem na tle rozwiązań konkurencyjnych.

Sama implementacja nie była łatwa. Przy okazji tworzenia mechanizmu musiałem dogłębnie poznać działanie kilku elementów jądra, a także uważać na różne subtelności takie jak właściwa synchronizacja czy optymalizacja.

…teoretyczna…

Oprócz pierwszego rozdziału o mechanizmach bezpieczeństwa systemu Chrome OS, musiałem napisać jeszcze z 70 stron :). Dalsza część tekstu powstawała w minionym semestrze, a jej treść w zasadzie odzwierciedlała postępy w pracy. Drugi rozdział dotyczył zatem istniejących rozwiązań oferujących usługi ochrony dostępu do wywołań systemowych i dlaczego są złe ;>. Dalej było standardowo – rozdział pt. „Projekt”, w którym rozważałem możliwe podejścia do tematu, „Implementacja”, w której skoncentrowałem się na specyfice programowania w przestrzeni jądra oraz „Testowanie”, w którym przeprowadzałem dosyć hardkorowe testy wydajnościowe. Na koniec pozostało napisanie wstępu i zakończenia i gotowe! Wygląda to jak spacerek, ale tak naprawdę to był maraton. Pisanie tekstów technicznych jest trudne, nawet bardzo trudne. Praktyka w pisaniu na blogu to niewiele, ponieważ styl języka jest całkowicie inny. Ostatecznie udało się jednak złożyć pracę na czas, 3 dni przed terminem.

…i rezultaty

Oprócz tytułu zawodowego, udało mi się zdobyć coś (ideologicznie) wartego znacznie więcej – wiedzę. Mogę śmiało powiedzieć, że udało mi się znacznie rozmnożyć moje zasoby wiedzowe, co uznaję za największy sukces całego procesu dyplomowania. Mówiąc krótko – jestem dumny z wykonanej przeze mnie pracy i chyba nie ma w tym nic złego. Mam też nadzieję, że równie przyjemnie będzie mi się pracowało nad pracą magisterską.

W tym miejscu zachęcam do przeczytania przynajmniej fragmentów mojej pracy (jak tylko zostanie ona opublikowana), a także śledzenia wszelkich „ubocznych” efektów dyplomowania :).

inż. Łukasz

Tak oto upłynął mi semestr siódmy, całkowicie inny od pozostałych. Można powiedzieć, że nawet przyjemny i interesujący. W końcu udało mi się otrzymać 3 nowe litery i kropkę przed nazwiskiem, a to dla mnie całkiem miłe osiągnięcie :).

Semestr

Na ten semestr został mi już tylko jeden przedmiot – algorytmy heurystyczne. Niewiele mogę jednak o nim napisać, gdyż (niestety?) nie bardzo się do niego przykładałem z powodu zaangażowania w pracę inżynierską. Ot przedstawienie, podsumowanie wiedzy o metoda metaheurystycznych i trochę obrzydliwej matematyki. Na plus można zaliczyć fakt, że udało mi się przy okazji poznać nowy język – R, potrzebny do realizacji projektu.

Na oddzielny akapit zasługuje seminarium dyplomowe, na którym każdy uczestnik miał okazję opowiedzieć o swojej pracy dyplomowej. Inicjatywa całkiem fajna, bo rozwijającą. Ogromna różnorodność tematów pozwala doszkolić się z innych, niż własna, dziedzin. Przyczepić można się tylko do dwóch rzeczy. Przede wszystkim każdy uczestnik miał tylko 20 minut na prezentację, co jest śmiesznie małą ilością czasu. Ciężko w 1/3 godziny przedstawić efekt wielu dni pracy, ale widocznie „tak musi być”. Druga sprawa to jakość przygotowanego przez uczestników materiału – często co najmniej „słaba”. Niemniej jednak, takich inicjatyw powinno być więcej. Niech nie tylko wykładowcy mają prawo głosu :).

Praca inżynierska

Zdecydowaną większość semestru spędziłem na pracy nad dyplomem. Poważny risercz, dużo pisania – zajmowało to kupę czasu i co ważniejsze chęci i siły. Z tego też powodu zaniedbałem całkowicie bloga. Po spędzeniu kilku godzin dziennie na pisaniu, perspektywa tworzenia (dobrowolnie) notki na bloga powodowała u mnie niemal odruch wymiotny. W każdym razie, efekt mojej pracy jest (przynajmniej dla mnie) więcej niż zadowalający. Kompletny, funkcjonalny moduł jądra oraz około 90 całkiem treściwych stron pt. „Nowoczesne mechanizmy bezpieczeństwa w systemie Linux” są zwieńczeniem niemal roku pracy. Co jednak najważniejsze praca została oceniona na bardzo dobry z wyróżnieniem czyli nie tylko mi się podobała :).

Studia, studia… i po studiach

Udana obrona – studia ukończone na bardzo dobry z wyróżnieniem zakończyły inżynierski etap mojej edukacji. Nie mam ochoty ich podsumowywać, gdyż myślę, że byłoby to nierzetelne. Prawdziwy obraz moich studiów tworzą komentarze do poszczególnych semestrów, do których linki można znaleźć poniżej:

Odpowiem jednak przy okazji na proste pytanie: czy żałuję? Nie, nie żałuję. Tych 7 semestrów poszerzyło moje horyzonty w wielu kwestiach i nauczyło wytrwałości. Mogło być jednak znacznie lepiej. Szkoda zmarnowanego potencjału.
Co teraz? Odpowiedź jest prosta – czas na studia magisterskie – znowu na kochanym Wydziale :). Myślałem oczywiście o zmianie miejsca, ale najnormalniej w świecie – nie chce mi się.
PS. Blog dorobił się dwóch nowych działów Projekty i Publikacje. Zobaczcie koniecznie!

Jak (wg mnie) uczyć się na studiach?

Sześć semestrów studiowania już za mną – to znaczy, że jestem już za połową. Dużo kolokwiów i egzaminów udało mi się już zaliczyć, zarywając przy tym jeszcze więcej nocy. To wszystko znaczy, że pewne doświadczenie w studiowaniu już mam i wydaje mi się, że już niewiele rzeczy jest w stanie mnie na studiach zaskoczyć ;). Wiem, że zagląda tu sporo studenckiej braci, dlatego postanowiłem dać kilka porad młodszym rangą od siebie :).

Semestry początkowe, czyli kurowa wszystkich nauk

Na chyba każdej uczelni technicznej pierwsze semestry składają się głównie z matematyki. Algebra, analiza, logika, statystyka – to standard. Semestry te są też podobno najtrudniejsze i na nich odpada najwięcej osób. Na mojej kochanej Uczelni z matematyki dawano nieobowiązkowe zestawy zadań, które później robione były na ćwiczeniach. Jak się okazało, najskuteczniejszym podejściem do sprawy było po prostu robienie ich samodzielnie wcześniej. Owszem, zabierało to dużo czasu: dzień przed ćwiczeniami widywałem wschody słońca, przy piwku i zeszycie z całeczkami; owszem było to nudne, a czasem wręcz niesamowicie irytowało; ale owszem – dawało to wybitne wyniki: dzień przed kolokwium wystarczyło przejrzeć wykonaną wcześniej pracę, a samo kolokwium wydawało się dziecinnie proste. Do matematyki podejście jest więc proste: ćwiczyć, ćwiczyć i jeszcze raz klepać schematy – a zaliczenie przyjdzie bez problemu.

Warto jeszcze wspomnieć dwa słowa o wykładach i ćwiczeniach. Na wykładach bardzo często dyktowana jest książka (z dokładnością do takich samych przykładów). Można więc pokusić się o absencje, jednak wtedy trzeba taką książkę załatwić, albo wziąć od kogoś notatki. Ja mimo wszystko uczęszczałem na wykłady, głównie dlatego że najmilej czyta mi się swoje własne pismo i żartobliwe rysunki :P. Co do ćwiczeń, to warto chodzić – głównie po to, żeby zweryfikować swoje rozwiązania i załapać punkty za aktywność.

Semestry dalsze, czyli pozostałe dobrodziejstwa inwentarza

Pozostałe przedmioty na studiach (pamiętajmy, że ciągle mówimy o informatyce) można podzielić na takie, które wymagają wiedzy (np. architektura komputerów, systemy operacyjne, grafika komputerowa) i takie które wymagają klepania schematów (np. teoria obwodów, teoria informacji, automatyka, optymalizacja). Co do drugiej (gorszej, nota bene) kategorii strategia jest taka sama jak dla matematyki – trzeba się po prostu tych schematów nauczyć, a później na kolokwium/egzaminie wyklepać. Tutaj niebywale przydaje się bank kolokwiów i egzaminów z ostatnich lat do poćwiczenia. Poza tym, nie trzeba chyba wspominać, że wiele zadań się po prostu powtarza :). Nauka schematów jest żmudna, ale nie jest trudna, dlatego też chodzenie na wykłady z przedmiotów „schematycznych” jest raczej zbędne – chyba że ktoś naprawdę lubi patrzeć jak się oblicza kolejną całkę na tablicy.

Dosyć już jednak narzekania, przejdźmy do przedmiotów wymagających wiedzy, czyli bardziej złożonej materii. W trakcie 6 semestrów nauki udało mi się wypróbować dwie strategie – opiszę więc każdą z nich.

Noc przed, zasada indukcji, od zera do bohatera

Strategia ta jest bardzo prosta. Zakłada ona, że da się wszystkiego nauczyć na egzamin/kolokwium w nocy przed takowym. Zwykle nie ma wtedy mowy o spaniu, trzeba mieć dużo samozaparcia i wytrwale siedzieć i czytać. Strategia ta działa i jest praktykowana przez wiele osób – z sukcesami. Ma ona jeden szkopuł – niestety trzeba mieć pewną, podstawową wiedzę wyniesioną z wykładów (albo z książek, tudzież doświadczenia). Dla przykładu uczenie się algorytmów „od zera” w 8 godzin jest zbyt męczące psychicznie = niemożliwe. Z drugiej strony, mi z podstawami sztucznej inteligencji się udało – z zerową wiedzą wyniesioną z wykładu ;). Skuteczność tej metody zależy więc od materii i osobistych predyspozycji.

Zastanówmy się teraz nad czymś takim: „a co jeśli jednego dnia mam n kolokwiów?” (n > 1). Słynna zasada indukcji studenta mówi, że jeśli student jest w stanie nauczyć się do n kolokwiów w nocy przed, to jest też w stanie nauczyć się do n+1 kolokwiów. Dlatego jeśli jesteś w stanie przygotować się do kolosa na noc przed, to z dwoma, trzema… też nie będziesz miał problemów :). Tutaj jednak warto wiedzieć o zasadzie Pareto. Noc może nie starczyć, aby nauczyć się na 100%, jednak pewien (poniekąd 20%) wkład w każdy z n podproblemów da nam wysoki (poniekad 80%) wynik.

Co natomiast robić, jeśli na wykładach nie pojawialiśmy się w ogóle, a kolokwium/egzamin zbliża się nieubłaganie? Cóż, innego wyjścia nie ma, jak tylko kuć wytrwale nie przez jedną, a np. przez trzy kolejne noce. „Od zera do bohatera” w 3 dni wydaje się być osiągalne, niezależnie od poziomu skomplikowania materii. Może to być jednak wyjątkowo wyczerpujące i niemiłe. Spróbowałem raz – udało się, ale rzeczywiście było niemiło.

Systematyczność

Systematyczność – tego słowa nienawidzą wszyscy uczniowe. Nauczyciele nieustannie, od lat powtarzają – ucz się systematycznie, a wyniki przyjdą same. Po 5 semestrach wykorzystywania zasady „noc przed”, na 6 semestrze postanowiłem spróbować (eksperymentalnie) uczyć się systematycznie każdego przedmiotu. Nie ze wszystkimi się udało, bo niektóre były zbyt ohydne, ale jednak z większością tak :). Efekty? Znakomite. Wyniki oscylujące w okolicy 100% były normą. Koszt? Ogromny. Wymagało to wytrwałego chodzenia na wykłady i codziennej powtórki (około dwugodzinnej) tego, co udało mi się tam nauczyć. Dostrzegłem też pewien pozytywny efekt uboczny: w końcu czułem, że do przedmiotów, które lubie przykładam się w stopniu zadawalającym.

Aurea mediocritas

„Jak więc żyć, drogi Łukaszu?” słyszę pytania z tłumu. Już stoicy znali na nie odpowiedź: złoty środek. Dla przedmiotów ze schematami należy uczyć się schematów – najlepiej tak, aby mechanicznie je odtwarzać, gdy ktoś o nie pyta. Dla nudnych, nieciekawych przedmiotów wymagających wiedzy warto stosować taktykę „olewczą”, czyli uczyć się na noc przed. Do przedmiotów interesujących i lubianych najlepiej uczyć się systematycznie.

W ten sposób pielęgnujemy swoje pasje i zainteresowania i zaliczamy kolejne przedmioty, utrzymując przy tym stan frustracji na rozsądnym poziomie.

Disclaimer

Przedstawione powyżej metody działały dla mnie znakomicie. Nie tylko pozwalały gładko zaliczać kolejne przedmioty, ale również dawały dobre wyniki (jeśli mierzyć je wysokością oceny). Warto jednak pamiętać, że nie każdy ma taki sam styl nauki. Niektórzy nie są wstanie przesiedzieć nocy nad książką, innym wystarczy tylko chwilowe spojrzenie na coś i już to potrafią. Do tego, moje doświadczenia opieram wyłącznie na moich studiach, które mogą być specyficzne, ze względu na kierunek czy wydział/uczelnię. Należy więc wypracować indywidualny tryb pracy, a powyższe metody potraktować jako pewną możliwość. Sukcesu więc nie gwarantuję, jednak z całego serca życzę :).

Tworzenie systemu operacyjnego – część 0×06: Porządki, GDT, VGA…

W szóstej odsłonie serii zajmę się małymi porządkami, które zaprocentują w najbliższej przyszłości. Przede wszystkim uporządkuję kilka spraw, wrócę raz jeszcze do GDT oraz napiszę kilka funkcji, które będą pomocne przy wypisywanu komunikatów diagnostycznych, których nigdy za wiele ;).

Raczkująca przenośność

Twórcy niektórych systemów operacyjnych stawiają sobie za zadanie dotarcie do możliwe (potencjalnie!) najszerszej rzeszy użytkowników. Tworzą oni implementacje dla różnych architektur procesorów i starają się, aby dodanie kolejnych było w miarę łatwe. Inni całkowicie na to leją, gdyż biznesowo patrząc – jest to nieopłacalne. Przykłady jednych i drugich łatwo wymyślić, więc nie będę ich tu podawał ;). W swoim systemie postanowiłem zrobić kroczek w stronę stworzenia przenośnego systemu operacyjnego – maksymalnie wykorzystuję język C, który jest przenośny (od mikrokontrolerów aż do dużych, „poważnych” procesorów), a minimalizuję użycie assemblera, który tej cechy nie posiada.

Magia typedef

Każdy, kto programował trochę w C i C++ wie jak bardzo przydatnym i potężnym narzędziem jest słowo kluczowe typedef. Każdy znany mi system operacyjny często i gęsto wykorzstuje „typedefowanie” – mam więc i ja :).

Wielokrotnie podczas tworzenia oprogramowania poziomu jądra potrzebne są nam typy, które posiadają ściśle określoną liczbę bitów – 8, 16, 32 itd. Typy o ustalonej długości służą do tworzenia flag, pól bitowych itp. Niestety specyfika architektur i co gorsza – kompilatorów powoduje, iż dany typ (int, short, long) ma często nieznaną z góry bitową długość. Można sobie jednak z tym poradzić tworząc odpowiednie definicje typów jak np. moje:

typedef unsigned int u32int;
typedef signed int s32int;
typedef unsigned short u16int;
typedef signed short s16int;
typedef unsigned char u8int;
typedef signed char s8int;

Dzięki temu, dla każdej architektury można stworzyć taki plik i podczas kompilacji włączać odpowiedni. Takie podejście ma jeszcze jedną zaletę – nazwa s8int (s od signed, 8 od liczby bitów i int od typu całkowitoliczbowego) jest bardziej wymowna niż char :). To pierwszy, malutki krok ku przenośności – wymaga on jednak konsekwencji w stosowaniu.

Opakowanie

W języku C nie da się zaprogramować wszystkiego – czasem trzeba skorzystać z instrukcji assemblera specyficznych dla danej architektury. Bywa jednak, że pewna instrukcja występuje na niemal każdej architekturze, jednak pod inną postacią. Warto wtedy opakować taką instrukcję w odpowiednią funkcję w języku C. Przykładem takiej instrukcji jest instrukcja zatrzymująca prace procesora – dla x86 jest to instrukcja hlt:

inline void hlt()
{
	asm volatile("hlt");
}

Opakowanie jak widać jest banalne, a może w przyszłości oszczędzić wiele kłopotów. Co więcej, możemy ją teraz swobodnie wykorzystywać w wielu miejscach w kodzie w C!

Warto jeszcze zauważyć, że używam składni tzw. inline assembly, która dla GCC jest bardzo specyficzna (czyt. paskudna). Jest jednak o tym dużo artykułów, więc ja się rozpisywać nie będę.

GDT – znowu…

Jakiś czas temu pisałem o multiboot, który ustawia odpowiednio tablicę GDT. Wszystko byłoby pięknie – jest jednak pewien problem – nie wiemy dokładnie gdzie znajduje się ta tablica, nie wiemy również, co tak naprawdę się tam znajduje. Warto więc ustawić ją jeszcze raz – po swojemu i w znanym miejscu, a do tego – używając głównie C. Na początek struktura deskryptora:

typedef struct gdt_descr
{
	u16int limit_low;
	u16int base_low;
	u8int base_middle;
	u8int access;
	u8int granularity;
	u8int base_high;
} __attribute__((packed)) gdt_descr_t;

oraz wskaźnika na samą tablicę:

typedef struct gdt_ptr
{
	u16int limit;
	u32int base;
} __attribute__((packed)) gdt_ptr_t;

W obu przypadkach używam atrybutu packed, który instruuje kompilator, aby nie stosował wyrównania naturalnego dla architektury (to pewien rozdzaj optymalizacji) – tylko aby bajty były ciasno upakowane koło siebie ;). Struktura powyższych typów powinna być jasna. Została ona szeroko omówiona w poprzenich częściach kursu. Pozostałe kwestie są już trywialne, na początek deklaracja tablicy i wskaźnika na nią:

#define GDT_LEN 5

static gdt_descr_t gdt[GDT_LEN];
static gdt_ptr_t gdt_ptr;

funkcja ustawiająca pojedynczy deskryptor:

static void gdt_set_desc(gdt_descr_t* descr, u32int base, u32int limit, u8int access, u8int granularity)
{
        descr->base_low = (base & 0xFFFF);
        descr->base_middle = (base >> 16) & 0xFF;
        descr->base_high = (base >> 24) & 0xFF;
        descr->limit_low = (limit & 0xFFFF);
        descr->granularity = ((limit >> 16) & 0x0F) | (granularity & 0xF0);
        descr->access = access;
}

oraz funkcja ustawiająca poszczególne deskryptory:

void gdt_init()
{
        gdt_set_desc(&gdt[0], 0, 0, 0, 0);                // null
        gdt_set_desc(&gdt[1], 0, 0xFFFFFFFF, 0x9A, 0xCF); // ring0 code
        gdt_set_desc(&gdt[2], 0, 0xFFFFFFFF, 0x92, 0xCF); // ring0 data
        gdt_set_desc(&gdt[3], 0, 0xFFFFFFFF, 0xFA, 0xCF); // ring3 code
        gdt_set_desc(&gdt[4], 0, 0xFFFFFFFF, 0xF2, 0xCF); // ring3 data

        gdt_ptr.base = (u32int) &gdt;
        gdt_ptr.limit = sizeof(gdt_descr_t) * GDT_LEN - 1;

        gdt_set(&gdt_ptr);
}

Warto zauważyć, że tym razem tworzymy dokładnie 5 deskryptorów. Pierwszy z nich to tradycyjnie deskryptor NULL, następnie mamy deskryptory kodu i danych dla przestrzeni jądra oraz deskryptory kodu i danych dla przestrzeni użytkownika. Wszystkie, oprócz NULL, rozciągają się oczywiście na całe 4GiB pamięci – różnią się tylko typem i prawami dostępu. Pozostała już tylko funkcja ustawiająca nową tablicę GDT, czyli gdt_set(), niestety tym razem należy skorzystać z kodu assemblera:

[GLOBAL gdt_set]

gdt_set:
        mov     eax, [esp+4]    ; get passed pointer
        lgdt    [eax]           ; load new GDT pointer

        mov     ax, 0x10        ; load all data segment registers
        mov     ds, ax
        mov     es, ax
        mov     fs, ax
        mov     gs, ax
        mov     ss, ax
        jmp     0x08:.flush     ; far jump to code segment
.flush:
        ret

kod ten jest jednak bardzo prosty i powinien być bez problemu zrozumiały.

VGA

Najstarsza metoda debuggowania programów (podobno odnaleziono ją na ścianach jaskini Lascaux) polega na wypisywaniu otrzymywanych wartości i „ręcznej” ich analizie. Niestety, w przestrzeni jądra jest to często jedyna dostępna możliwość. Warto więc zadbać o taką możliwość od samego początku. W swoim systemie (przynajmniej na razie) wykorzystuję podstawowe możliwości kart zgodnych z VGA, tak jak robiłem to już wcześniej. Funkcja inicjująca wykrywa typ monitora i ustawia odpowiedni adres pamięci zamapowanej na pamięć VGA. Przy wykrywaniu korzystam z pomocnych informacji, które pozostawił BIOS. Ustawiam też wirtualną pozycję kursora:

#define SCREEN_HEIGHT 25
#define SCREEN_WIDTH 80

static u16int* vga_mem;
static int cursor;

void vga_init()
{
        cursor = 0;

        if ((*((volatile u16int*) 0x410) & 0x30) == 0x30) // detecting monochrome monitor
                vga_mem = (u16int*) 0xB0000;
        else
                vga_mem = (u16int*) 0xB8000; // it's color
}

Powyżej widać też definicje wysokości i szerokości typowego monitora VGA, czyli 80×25 znaków.

Pierwszą „piszącą” funkcją jest funkcja czyszcząca ekran:

void vga_cls()
{
        int i;
        for (i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT; ++i)
                *(vga_mem + i) = (u16int) 3872; // ((((0 << 4) | (15 & 0xFF)) << 8) | 0x20) // white spaces on black background
}

Jak widać, po prostu piszę 80*25 spacji na czarnym tle ;). Jeśli sposób pisania po ekranie nadal jest niejasny, to proponuję spojrzeć na ten wpis.

Najważniejszą funkcją, jest jednak funkcja produkująca napisy na ekranie. Jest ona dosyć skomplikowana, gdyż sterownik VGA nie potrafi wypisywać znaków nowej linii \n, tabulacji \t oraz powrotu karetki \r - są one obsługiwane oddzielnie:

void vga_puts(const char* str)
{
	// white letters on black background
	const u16int attribute = 3840; // ((((0 << 4) | (15 & 0x0F)) << 8))

	int i = 0;
	while (str[i] != '\0')
	{
		if (cursor == SCREEN_WIDTH * SCREEN_HEIGHT)
		{
			vga_scroll();
			cursor = SCREEN_WIDTH * (SCREEN_HEIGHT - 1);
		}

		switch (str[i])
		{
		case '\n':
			cursor = cursor + 80 - cursor % 80;
			break;
		case '\r':
			cursor = cursor - cursor % 80;
			break;
		case '\t':
			// increment to align to 8
			while ((cursor % 80) % 8 != 0)
				++cursor;
			break;
		default:
			vga_mem[cursor] = (u16int) (attribute | str[i]);
			++cursor;
		}

		++i;
	}
}

W przypadku typowego znaku po prostu wpisuję odpowiednią wartość do pamięci pod adresem vga_mem[cursor] i inkrementuję pozycję kursora. Dla \n dodaję 80 (długość linii) a następnie odejmuję tyle, aby powstała liczba była podzielna bez reszty przez 80 - czyli po prostu przechodzę do kolejnej linii. Dla \r robię operację podobną - tyle, że nie dodaję 80, co powinno być oczywiste. Dla \t dodaję do pozycji kursora 1 dopóki pozycja w aktualnym wierszu jest niepodzielna przez 8 (typowe zachowanie tabulacji w systemach UNIX).  Na początku funkcji widać jeszcze obsługę sytuacji, gdy zapełnimy cały ekran znakami - przenoszę wtedy nasz wirtualny kursor na początek ostatniej linijki i wywołuję wtedy scroll(), która przepisuje wiersze "o jeden do góry ekranu" - pierwszy wiersz zostaje nadpisany drugim itd., ostatni wiersz zostaje wyczyszczony:

static void vga_scroll()
{
        int i;
        // rewrite lines one up
        for (i = 0; i < SCREEN_WIDTH * (SCREEN_HEIGHT - 1); ++i)
                vga_mem[i] = vga_mem[i + SCREEN_WIDTH];

        // clear last line
        for(i = 0; i < SCREEN_WIDTH; ++i)
                vga_mem[SCREEN_WIDTH * (SCREEN_HEIGHT - 1) + i] = 3872; // ((((0 << 4) | (15 & 0xFF)) << 8) | 0x20) // white spaces on black background
}

Do boju

Mając pod kontrolą najważniejszą strukturę danych - GDT oraz odpowiednie (acz niekompletne) narzędzia do debuggowania możemy śmiało zagłębiać się w kolejne mechanizmy architektury x86. W końcu, za każdym razem, gdy coś nie zadziała - będziemy mogli sprawdzić dlaczego :).

Typowo, kompletny kod, w którego organizacji zaszły spore zmiany, jest dostępny tu:

git clone git://github.com/luksow/OS.git --branch 0x06

oraz bezpośrednio do obejrzenia tu.