2013/12/12

つくったVim PluginとつかったVim scriptのはなし

この記事は Vim Advent Calendar 2013 の 12日目の記事です。

もう12月も半ばですね。
みなさまは年の暮れに向けていかがお過ごしでしょうか。
私の場合、Plugin作りがなかなか進まず、苦しい年末が近づいております。

さて、今回は自分で作ったPlugin4つの紹介とその時に知ったVim scriptについてのことを書こうと思います。

まずは一つ目です。
Vim scriptをVim Pluginとするにはディレクトリを分けるなど Vim Pluginとしてのルールがあります。
ですが、「あっ、これPluginにしよう!」と思った時にmkdirやtouchコマンドを連打するのは面倒です。
:help write-plugin にもある通り、Pluginとするにはディレクトリを分ける必要があります。
直ぐにパッと作って行きたい、Pluginを作りはじめるまでをカイゼンしようというわけです。

そんなときに使うために作ったのがこれです。
mopp/layoutplugin.vim
Vimからディレクトリ、スクリプトファイル、README.mdをパッと作ってくれます。
スクリプトファイルの中身もテンプレ的に出力してくれます。


2つ目です。
githubをふらふらしていた時にたまたま見つけた、
数年前にmattnさんが作ったgooglesuggest-complete-vimをneocomplete.vim向けにラップしました。
mopp/googlesuggest-source.vim
自動でgoogle補完力で入力ができます。
個人的に5分で出来たにもかかわらずなかなか面白いなあと感じております。
ただ少々不安定なのは通信をするからでしょうか…
そういうときはインサートモードで<C-U>するとよいです。


3つ目です。
molokaiのような色合いが好みなのですが
コメントの色など不満が幾つかあったのでmolokaiを元に自分のカラースキームを作りました。

mopp/mopkai.vim
もぷかいと読んでやってください。
molokaiよりも強めのカラーリングのつもりです。
自分のためのカラースキームなのでこれからもガンガンいじっていく予定です。

4つ目です。
先日のvimrc読書会で誰かこれをPlugin化という話が挙がっていたのでささっとしておきました。
mopp/autodirmake.vim
:e new_dir/text.txt と編集した際にnew_dirが存在しないディレクトリだとVimはファイルを保存できません。
このPluginを入れておけば、保存時にディレクトリを作成してくれます。


次にPluginを作ってる時に知ったVim scriptについてです。
自分がメモとして書き留めていたものを、色がついて見やすいのでgistにまとめました。
詳しくは:helpで見たほうがよいでしょう。

波括弧付き変数とかすごいですね
Pluginをどんどん生み出している人からすれば当たり前かもしれませんが
私は、helpを読破していないのでVimの知らない機能がまだあります。
人のPluginを読むとなんだこのコマンドは…というのもよくあることです。

Vim Plugin力もレベルアップしていかねばなりませんね。

というところで、今回は筆を置くことにします。

Happy Vimming !

2013/12/06

OSの超簡単なメモリ管理を実装するおはなし

この記事は Aizu Advent Calendar 2013 6日目の記事です。
前日は「Aizu Advent Calender 5日目(ダイエット成功したかも知れません)」でした。

おはようございます。
もぷりです。
最近すっかり寒いですが、皆様いかがお過ごしでしょうか。
私は今、胸部に痛みを感じつつキーを叩いております。

さてさて、今年もAdventな季節がやってまいりました。

今回は自分の作ってるOSでとりあえず実装した簡単なメモリ管理について書きます。
間違いなどの指摘があれば@Mopp_jpでもissuesでもなんでもよいのでぜひ言ってください。

リポジトリはこれです。

まず、メモリの管理とは
「OS内でハードウェアからのメモリ情報を使って
動的なメモリ確保を行えるようにする。」
ということです。

もっと簡単に言うと使っているのか使っていないのかを自動で判断してメモリ割り当てをしてくれるって意味です。


順を追って説明をします。

まず、OSはブートローダというOSを起動するだけ+αのソフトウェアから起動されます。
具体的にはgrubとかLILOですね。
で、このブートローダはBIOSが起動します。

BIOS → ブートローダ → OS → ζ*'ヮ')ζ<うっうー

このように起動していきます。
ちなみに、もぷりんOSでは色々とめんどかったのでgrubから起動されること前提で作っています。

先に言ったように、ブートローダはOSを起動するだけ+αです。
ですが、とても大切ですので簡単に説明します。

OSの実行ファイルをデバイスから探す
OSの実行ファイルをメモリに読み込む
ハードウェア情報、BIOSコールの戻り値などをメモリに置いておく
読み込んだOSの実行ファイル先頭部分へジャンプ

この4ステップです。
シンプルですねー(※1ステップ目以外)

このOSが起動した時点で、メモリについて考えてみます。
はい、なにもないですね。
ですので、とりあえずOSはセグメントというものを設定します。
セグメントもメモリに関係するものでメモリの使用用途や権限を定めるものです。
(※セグメントも大事なことなのですが今回は説明しないですすいませんです。)

他にも割り込みなどいろいろと設定するものがあります。
どれもこれもコンピュータ上のデータであるからにはメモリ上に存在していなければなりません。
しかし、まだ、動的メモリ確保は行えませんので以下のようにします。


メモリを直書きしてキャストです。
変数をグローバルにおいても別にいいのですが、配列などの大きなデータを入れてしまうのはサイズ的に気が引けます。
出来れば、ポインタだけで済ませたいです。
場合によってサイズが変化する場合などなおさら動的に確保して無駄を減らしたいです。

そもそも、こういうことをたくさんやるのは良くないですし
いちいちアドレスを気にするのも面倒です。

そこで、やっと本題のメモリ管理です。
メモリ管理の初期化は2ステップです。
メモリ情報取得
それを元にメモリ空間をリスト構造化

使うときには普通のC言語と同様にmallocとfreeで扱えます。

1ステップ目
BIOSコールを使って、コンピュータのメモリ情報を取得します。
grubであれば取得データを渡してくれます。
この情報にはメモリの領域が使えるか使えないかという部分が入っています。

使えない部分というのはブートローダに処理が渡った際、既にデータが置いてあって、書き込みされると困る部分です。
そこには割り込みベクタなどがあります。

これは特に問題ないですね。

2ステップ目
メモリ管理には有名なものでビットマップを用いるものと連結リストを用いるものがあるようです。
簡単に説明をします。

ビットマップ方式
    固定長(4KBくらい)でメモリを区切って、その一つを1bitに割り当てて、使っている、使っていないを判断します。
リスト方式
    可変長でメモリを区切って、ここからここまで使ってる、ここからここまで使っていない、という風に判断します。

後々便利そうだったのでもぷりんOSでは連結リストを使用しました。
ファイルはこいつです。
https://github.com/mopp/Axel/blob/advent/src/doubly_linked_list.c

さて、コードをさらーっと見ていきます。

ここでOS起動時の初期化で呼ばれる関数はinit_memory()です。
引数にはgrubのくれるメモリ情報、とそのサイズが渡されます。

L57init_memory_list()で、メモリ管理に使用するデータとリストのノードを初期化します。
> dlst_nodes = (struct dlinked_list_node*)(get_kernel_end_addr() + sizeof(Memory_manager));
> mem_info = (Memory_info*)(dlst_nodes + sizeof(struct dlinked_list_node) * MAX_MEM_NODE_NUM);

> mem_manager = (Memory_manager*)get_kernel_end_addr();
これはカーネル(OS)の読み込まれた末尾のメモリを使用するためにアドレスの計算をしています。
get_kernel_*関数の中身を見ればわかりますが、メモリ直書きと大差ないです。

次にL60-L80でメモリ情報を元にリスト構造化します。
set_meminfo()関数を使って、ベースアドレスとそこからの長さをリストのデータに持たせます。

その後にL82-L117でカーネル部分のメモリを使用中にしておきます。
ここを忘れては元も個もありません(TODOは見なかったことにしてください)

初期化はこれだけです。

あとは使うだけですのでmallocとfreeを用意します。


mallocでは受け取ったサイズが入る領域を持つノードを探して行って、見つかったらその先頭部分から新たにノードを作り、使用中にします。
これをfirst-fit方式といいます。
手っ取り早くていいですね。

freeは確保時に返したアドレスを探していき、見つかったら空き領域とし
可能ならば前後のノードとまとめる、ということを行います。


はい、以上です。
OSのメモリ管理なんてもっと難しいのかと思っていたら案外そんなことはありません。
わかりにくかったらそれはきっとこの記事が悪いのでしょう。

といっても、はりぼてにすらならない穴だらけOSなのできちんと作っていきたいです。

明日、Aizu Advent Calendar 2013、7日目はmotiさんです。