SolarisのCDE環境に付属する謎(?)のツール、アプリケーションビルダ

遅ればせながら岩手県立大学 Advent Calendar 2020 第9日目の記事です。
今日はデスクトップ環境CDEに含まれている謎(?)のツール、「アプリケーションビルダ」の話をしようと思います。
(例によって我々の世界とは時間軸が完全に一致していない可能性があります...)

f:id:furandon_pig:20201216072956p:plain

GUIアプリケーションビルダ?

ソフトウェア演習で利用しているSolarisには、「アプリケーションビルダ」という謎のツールが付属しています。謎、というのは、このツールの使い方がイマイチ良く分からないのに加え、マニュアルを見てもどうGUIを構築するのかがやはり見えてこない点にあります。

man dtbuilder によると、どうやらCDE向けのGUI管理機能を備えたアプリケーション構築ツールのようです。

$ man dtbuilder
User Commands                                        dtbuilder(1)

Name
     dtbuilder - the CDE Application Builder

SYNOPSIS
     dtbuilder [projectfile]

DESCRIPTION
     The dtbuilder utility is an interactive application develop-
     ment tool and user interface management system for CDE.
     Known more fully as the CDE Application Builder, dtbuilder
     is designed to make it easier for developers to construct
     applications that integrate well into the CDE.  It provides
     two basic services - aid in assembling Motif objects into
     the desired application user interface and generation of
     appropriate calls to the routines that support CDE desktop
     services (e.g. ToolTalk, sessioning, Help).

debuilder コマンドでアプリケーションビルダを起動できます。

$ which dtbuilder
/usr/dt/bin/dtbuilder
$ dtbuilder &

なにやらそっけない感じのウインドウが表示されます。

f:id:furandon_pig:20201216072952p:plain

アプリケーションビルダでGUIを構築してみる

試しに簡単なGUIを作ってみます。左側の「ウインドウ」のアイコンをドラッグすると、「モジュール名」というダイアログが表示されます。どうやらこのようにしてアプリケーションウインドウを作ってゆくようです。

さらに「コントロール」ペインからボタンやラベルといったよく見かけるGUI部品をウインドウに配置してみます。

f:id:furandon_pig:20201216073031p:plainf:id:furandon_pig:20201216073027p:plain

とりあえずビルドしてみる

ビルドはどうすれば良いのだろうと思っていたのですが、どうやらアプリケーションビルダのメニューから「ファイル(F)」-「コードジェネレータ(G)...」で表示されるダイアログでコードの生成とmakeの実行まで行えることが分かりました。

f:id:furandon_pig:20201216073020p:plainf:id:furandon_pig:20201216073016p:plain

が、何やら make の実行でビルドエラーが出ます...。

f:id:furandon_pig:20201216073013p:plain

落ち着いてエラーメッセージを読むと、 DTHELP_WARNING_DISABLED マクロを定義してビルドすると良いよ!的なことが書いてあります。 #define で指定する方法とCFLAGSに -DDTHELP_WARNING_DISABLED を追加するいずれかの方法で対応できそうだったので、今回はCFLAGSでマクロを定義する方法にしました。

$ diff -u Makefile.ORIG Makefile
--- Makefile.ORIG       Mon Dec 14 07:41:50 2020
+++ Makefile    Mon Dec 14 07:42:30 2020
@@ -30,7 +30,7 @@
         ALLX_LDFLAGS = -L$(ALLX_LIBPATH) -R$(ALLX_LIBPATH)
         LOCAL_LIBRARIES = -lDtWidget -lDtHelp -lDtSvc -lXm -lXt -lXext -lX11

-        CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(STD_DEFINES) $(ANSI_DEFINES)
+        CFLAGS = $(CDEBUGFLAGS) $(INCLUDES) $(STD_DEFINES) $(ANSI_DEFINES) -DDTHELP_WARNING_DISABLED
         CCFLAGS = $(CFLAGS)
         LDLIBS = $(SYS_LIBRARIES)
         LDOPTIONS = $(CDE_LDFLAGS) $(ALLX_LDFLAGS)

無事にビルドが通りました!

f:id:furandon_pig:20201216073011p:plain

文字化けとの闘い

ビルドが通ったのは良いのですが、アプリケーションを実行してみるとボタンやラベルが文字化けしています...。

f:id:furandon_pig:20201216073008p:plain

おそらくどこかに多言語向けのコード生成を行わせるようにする設定があるのでしょう。アプリケーションビルダのメニューを見ると、「エディタ(d)」-「アプリケーション・フレームワーク(A)」というメニューがあります。

f:id:furandon_pig:20201216073005p:plain

そこには「国際化」という項目があり、デフォルト設定では「使用する:」のチェックが外れていました。このチェックを入れて再ビルドしてみます。

f:id:furandon_pig:20201216073002p:plain

今度は無事に文字化けせずに表示できました!

f:id:furandon_pig:20201216072959p:plain

まとめ

デスクトップ環境CDEに含まれているツール、アプリケーションビルダを簡単に触ってみました。実はこのツールはMotif)というGUIライブラリを利用してアプリケーションを構築するためのもので、どうやら9日目の記事で紹介したJava Swingよりもちょっと古いお作法でのGUIアプリケーション開発になるようなイメージです。

機会があれば、このアプリケーションビルダを利用してちょっとしたサンプルを作ってみたいと思います。

Java SwingでGUIを手書きする話

岩手県立大学 Advent Calendar 2020 第9日目の記事です。
今日はソフトウェア演習ではJavaGUIを手書きするという話をしようと思います。
(ただし我々の世界とは時間軸が完全に一致していない可能性があります...)

Java SwingでGUIを手書きする

ソフトウェア演習ではJavaを用いたプログラミングの授業が行われます。
CLIで動作するアプリだけでなく、SwingというJavaGUI用クラスライブラリを用いたアプリケーション作成の課題が出されたりします。

Hello,World的なGUIアプリケーション

GUIアプリは以下のような感じで手書きします。JBuilderのお試し版をインストールして動かしている人もいますが、メモリが128MBの環境ではJBuilderのようなIDEはだいぶ重たい動作になってしまいます...。

import javax.swing.JFrame;
import javax.swing.JButton;

public class Hello extends JFrame {
    Hello() {
        super("hello");
        getContentPane().add(new JButton("Hello,World."));
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }
    public static void main(String... args) {
        new Hello();
    }
}

そのためソフトウェア演習ではMuleというemacsへの多言語対応版エディタを使ってソースコードを書いています。人によってはよりコンパクトなエディタであるviを使ったりもするようです。
デスクトップ環境のCDEに付属しているdtpadというメモ帳風のエディタも試してみたのですが、さすがにこれでソースコードを書くのは少々骨が折れます...。

エディタの話を始めると大論争がおこるという都市伝説がありますが、個人的にはviの基本的な使い方を抑えておくと後々つぶしが効く(?)感じです。

Swing GUIを手書きする場合のコツ

そしてSwing GUIを手書きするという点についても、それほど難しい感じではありません、以下のような感じでBorderLayoutにボタンやラベル、テキストエリアを追加してゆくことでUI部品の配置やウインドウリサイズ時の再配置が動的に行われるようになります。

f:id:furandon_pig:20201210213640p:plain

私もSwingを使いこなせているワケではありませんが、ちょっとしたGUIアプリケーションを作成するだけであれば、以下のクラスの使い方を把握しているだけで充分対応できるという印象です。

GUI部品はどのアプリケーションでも似たような使い方になるので、イディオム的な使い方のサンプルを用意しておくと、テンプレート的な感じでソースコードを利用できるのでおススメです。

ソフトウェア情報学部の計算機環境

遅くなってしまいましたが岩手県立大学 Advent Calendar 2020 第4日目の記事です。
今日は学内でのソフトウェア演習で用いられている環境の紹介をしようと思います。
(ただし我々の世界とは時間軸が完全に一致していない可能性があります...)

学内の計算機環境

ソフトウェア情報学部では、Sun MicrosystemsSolarisというOSが利用できるようになっています。このSolaris環境でC言語シェルスクリプトPerlJavaを用いたプログラミングの授業が行われています。また、LaTeXという組版システムもインストールされており、これを用いてレポートを作成したりします。

f:id:furandon_pig:20201209025004p:plain

ちなみに、UNIXの系譜で見るとSolarisは当初BSDをベースにしており、のちにSystemVベースになったという経緯があります。BSD系のOSでは、デフォルトシェルがtcsh(Cシェルの機能拡張版)なのですが、学内のSolaris環境ではbash(Bourne Shellの機能拡張版)がデフォルトシェルに設定されています。Linux等でもbashがデフォルトシェルになっていたりするので、それぞれの環境を行き来する場合でも挙動の差異にあまり悩まされなくて済みそうです。

学生一人に1台のSolarisマシンが割り当てられるようになっており、各マシンの /usr/local 以下にソースコードからビルドしたアプリケーションをインストールして利用することも可能です。とはいえ、ソースコードからビルドしようとすると、まず最初に関連ライブラリをインストールするところから始める必要もあったりするのでちょっと大変です...(逆に考えると、ビルド力の向上に役立つと言えるかもしれません)。 学内のSolaris環境を利用してどんなことができるかは、以降のアドベントカレンダーで紹介させてもらえればと思います。

JustTechTalk#06 参加メモ(1/3)「スマイルゼミの裏側:データベース編」

JustTechTalk#06 スマイルゼミの裏側(DB編)とRDBMS最新動向に参加してきました。 タイトルにもある通り、今回はDB関連の話がメインで以下の3つの発表がありました。

  • スマイルゼミの裏側:データベース編
  • OSS DBの最新情報
  • Amazon独自のDBマネージメントシステム

全部まとめると長々とした内容になってしまうので、今回は発表内容ごとにブログの記事を分けてみます。 (一つにまとめると後から自分で見返す時も大変ということに今更ながら気がついたのです...)

スマイルゼミの裏側:データベース編

ジャストシステムが運営する「スマイルゼミ」のサービスの裏側に関する内容でした。 スマイルゼミのサービスはTomcat+PostgreSQL 9.3で構築されており、今回はDB的な意味でやらかしてしまった話を聞くことができました。

スマイルゼミについて

  • スマイルゼミは小学生と中学生でニーズが異なる
    • サーバとクライアントの構成も小、中学生向けで別物というくらい異なっている
  • アクセスのピーク時間にも違いがあり、基本的に朝と夜にピークの山がある
  • 小学生向けのサーバでは朝の6:00〜8:00前くらい、中学生だと夜にピークがある

DBでやらかしてしまった話

DBでやらかしてしまった話として、unionにまつわる2つのケースが解説されていました。

viewの中のunionが悪さをしていた話

  • ある日のこと、平日のピークではない時間帯に負荷が急上昇した
  • 前日にhotfixを当てており、これが問題の引き金になった模様
  • 内部のバッチ処理で1300万行のシーケンシャルスキャンが発生していた
  • 調べてみると怪しいviewがあった。
    • (4000行のviewとのことで、業務だとそれくらい大きなviewを使うものなのですね...)
    • viewを使うようにプログラムを変更しており、viewを使うとオプティマイザが絞り込みをしなくなってしまう
    • さらに、viewの中でunionを使っており、これが性能劣化の原因であった
      • (ちょっと記憶と手元のメモが曖昧。viewの中でunionしたことで、オプティマイザが働かなくなった、という話かも)
  • 対策として、前日の学習結果の集計をview定義の段階で学習日で絞った

(今度は逆に)unionで問題解消できた話

  • スマイルゼミのサービスとして、「みまもるトーク」というLINE的(?)なサービスがあるとのこと
  • これを中学生向けにも展開するため、ユーザ認証関連のSQLを修正した
    • WHERE句に小学生、中学生、親の条件を追加する形での修正
  • すると実行計画が狂ってしまい、インデックスが使用されなくなりシーケンシャルスキャンが発生
  • 対策として、小学生、中学生、親のそれぞれで行を絞り込んでからunionする方法で問題解消

得られた教訓

  • unionしている箇所の変更は慎重に行う必要がある
    • また、unionしてもよいのは中間結果が小さい場合のみ
  • viewの中でのunionは危険

まとめ

JustTechTalk#06 参加メモを書いてみました。他の2つの発表についても順次メモをまとめてみます。 DB関連のやらかしはケーススタディとして聞いた瞬間は「なるほど、自分も気をつけよう」と思うのですが、やはり実際にハマってみないと身につかないため、view+unionで実際に性能劣化が発生する様を手元の環境で試してみようと思います。

Linuxカーネルもくもく会#21に参加してきました

Linuxカーネルもくもく会 #21に参加してきました。iij/ipgenというパケットジェネレータで使用されている、高速パケットI/Oフレームワークの"netmap"に興味が湧きつつあり、少しずつソースコードを読み進めています。 今回と前回のもくもく会でnetmapのLinux実装部分のコードを読んでみたので、把握できた内容を簡単にまとめてみました。

netmapのコードはGitHubから取得できます。現時点ではLinux,FreeBSD,Windows環境向けにnetmapが実装されています。ちなみにnetmapは当初FreeBSDで開発されていたこともあり、netmapのコードはFreeBSDカーネルにマージされています。

Linuxにおけるopen("/dev/netmap",...)処理

さっそくLinuxにおけるnetmapの実装を見てみます。netmapのソースコードには内部構造の詳しい解説コメントが記載されており、実装の理解の助けになります。例えばnetmap.cには以下のコメントがあり、Linuxではlinux_netmap_open()から見て行くと良さそうです。

sys/dev/netmap/netmap.c
/* --- internals ----
 *
 * Roadmap to the code that implements the above.
 *
 * > 1. a process/thread issues one or more open() on /dev/netmap, to create
 * >    select()able file descriptor on which events are reported.
 *
 *      Internally, we allocate a netmap_priv_d structure, that will be
 *      initialized on ioctl(NIOCREGIF). There is one netmap_priv_d
 *      structure for each open().
 *
 *      os-specific:
 *          FreeBSD: see netmap_open() (netmap_freebsd.c)
 *          linux:   see linux_netmap_open() (netmap_linux.c) 

処理の流れを把握するため、linux_netmap_open()の関数呼び出し階層を示します。

LINUX/netmap_linux.c:
1057 static struct file_operations netmap_fops = {
1058     .owner = THIS_MODULE,
1059     .open = linux_netmap_open,
1060     .mmap = linux_netmap_mmap,
1061     LIN_IOCTL_NAME = linux_netmap_ioctl,
1062     .poll = linux_netmap_poll,
1063     .release = linux_netmap_release,
1064 };

関数の呼び出し階層は以下のようになっています。

-> LINUX/netmap_linux.c:linux_netmap_open()
  -> sys/dev/netmap/netmap.c:netmap_priv_new()
    -> LINUX/netmap_linux.c:nm_os_get_module()

linux_netmap_open()は帰り値として常に0を返すようです。変数errorは握りつぶされている気がする...。

1036 static int
1037 linux_netmap_open(struct inode *inode, struct file *file)
1038 {
1039         struct netmap_priv_d *priv;
1040         int error;
1041         (void)inode;    /* UNUSED */
1042
1043         NMG_LOCK();
1044         priv = netmap_priv_new();
1045         if (priv == NULL) {
1046                 error = -ENOMEM;
1047                 goto out;
1048         }
1049         file->private_data = priv;
1050 out:
1051         NMG_UNLOCK();
1052
1053         return (0);
1054 }

netmap_priv_new()はnetmap用の構造体(struct netmap_priv_d)用のカーネルメモリを確保し、linux_netmap_open()に返します。 先ほどの変数errorの値はlinux_netmap_open()から参照できなさそうですが、file->private_data == NULLの判定をエラーが発生しているかどうかは判定できそうです。

 959 struct netmap_priv_d*
 960 netmap_priv_new(void)
 961 {
 962         struct netmap_priv_d *priv;
 963
 964         priv = malloc(sizeof(struct netmap_priv_d), M_DEVBUF,
 965                               M_NOWAIT | M_ZERO);
 966         if (priv == NULL)
 967                 return NULL;
 968         priv->np_refs = 1;
 969         nm_os_get_module();
 970         return priv;
 971 }

nm_os_get_module()は自身のモジュールを取得するだけの処理です。

LINUX/netmap_linux.c:
  63 void
  64 nm_os_get_module(void)
  65 {
  66         __module_get(THIS_MODULE);
  67 }

処理がlinux_netmap_open()に戻ってきたのち、確保したstruct netmap_priv_dへの参照をfile->private_dataに設定します。

1036 static int
1037 linux_netmap_open(struct inode *inode, struct file *file)
1038 {
1039         struct netmap_priv_d *priv;
...
1049         file->private_data = priv;
1050 out:
1051         NMG_UNLOCK();
1052
1053         return (0);
1054 }

linux_netmap_open()の変数errorについて

linux_netmap_open()内の変数errorは握りつぶされている(呼び出し元に変数errorの値が渡らない)ように見える件、例えばLinuxのwrite()に対応する関数ではエラー値を負値にしてreturnしています。これに倣うとlinux_netmap_open()でもreturn (-ENOMEM);とするのが良いのかもしれません。

linux-4.5/fs/read_write.c:
 617 SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
 618                 size_t, count)
 619 {
 620         struct fd f = fdget_pos(fd);
 621         ssize_t ret = -EBADF;
 622
 623         if (f.file) {
 624                 loff_t pos = file_pos_read(f.file);
 625                 ret = vfs_write(f.file, buf, count, &pos);
 626                 if (ret >= 0)
 627                         file_pos_write(f.file, pos);
 628                 fdput_pos(f);
 629         }
 630
 631         return ret;
 632 }

Linuxカーネルmalloc()に対するグルーコード

netmap_priv_new()でmalloc()を呼んでいます。このmalloc()はLinuxでもBSD系と同じ引数で呼び出せるよう、ラッパーコードを挟んでいます。netmapはFreeBSDで実装されたこともあり、グルーコードの形で既存の処理を変更することなく別プラットフォームへの移植を行っている、ということですね。

sys/dev/netmap/netmap.c:
 959 struct netmap_priv_d*
 960 netmap_priv_new(void)
 961 {
 ...
 964         priv = malloc(sizeof(struct netmap_priv_d), M_DEVBUF,
 965                               M_NOWAIT | M_ZERO);
 966         if (priv == NULL)
 967                 return NULL;
 ...
 971 }

*_glue.hで各プラットフォーム向けのmalloc()ラッパーコードが実装されています。

$ global malloc
LINUX/bsd_glue.h
WINDOWS/win_glue.h

Linux/bsd_glue.hではkmalloc()へのラッパーになっています。

LINUX/bsd_glue.h:
304 /*
305  * in the malloc/free code we ignore the type
306  */
307 /* use volatile to fix a probable compiler error on 2.6.25 */
308 #define malloc(_size, type, flags)                      \
309         ({ volatile int _v = _size; kmalloc(_v, GFP_ATOMIC | __GFP_ZERO); })

WINDOWS/win_glue.hではwin_kernel_malloc()を挟んでExAllocatePoolWithTag APIを読んでいます。

WINDOWS/win_glue.h:
315 /*-------------------------------------------
316  *      KERNEL MEMORY ALLOCATION and management
317  */
...
321 #define malloc(size, _ty, flags)                win_kernel_malloc(size, _ty, flags)
...
325 /*
326  * we default to always allocating and zeroing
327  */
328 static void *
329 win_kernel_malloc(size_t size, int32_t ty, int flags)
330 {
331         void* mem = ExAllocatePoolWithTag(NonPagedPool, size, ty);
332
333         (void)flags;
334
335         if (mem != NULL) { // && flags & M_ZERO XXX todo
336                 RtlZeroMemory(mem, size);
337         }
338         return mem;
339 }

まとめ

Linuxにおけるnetmapのopen()に関する処理を追いかけてみました。linux_netmap_open()は比較的シンプルな実装になっています。netmapのソースコードには処理の流れやデータ構造の詳しい説明がコメントの形で記載されており理解の助けになります。

第35回「ネットワーク パケットを読む会(仮)」参加メモ

第35回「ネットワーク パケットを読む会(仮)」に参加してきました。

今回は「パケットジェネレータipgenから見るnetmap」という内容で、ipgennetmapに関するネタで発表してきました。

スライドで解説しているテスト用環境の構築手順はQiitaの記事にまとめてあります。ipgenが使用しているnetmapは面白そうな機能なので、いろいろと調べてみたいと思います。

勉強会メモ

以下は簡単ではありますが、勉強会のメモです。

この勉強会では、『ネットワークパケットを読む』と銘打ってあるように、毎回パケットキャプチャツールの更新情報についての解説があります。今回は以下のツールについてアップデート情報の解説がありました。

  • Wireshark 2.0.3が4/22にリリースされている
  • NetworkMiner
    • NetworkMiner 2.0がリリースされている
    • 2.0での変更点として、MIME Typeがバイナリなファイル(x-msdos-program等)の扱いが挙げられる。
      • これまでは.exeや.jar等のファイルは、拡張子を書き換えることで直接実行させないようになっていた
      • しかし、2.0からはこの機能がなくなっているため、安易にファイルリストのファイルを開くと悪意のあるファイルを実行してしまう恐れがあるので注意が必要
        • 機能が無効化された理由は、"Defang Executables"という有償版の機能に格上げ(?)されたため
  • Microsoft Message Analyzer
    • 公式のblogがあり、ツールの使い方や機能が紹介されているので定期的にチェックするとよさげ
  • Ostinatoというパケットジェネレータが存在するとのこと

他にも、とある通信機材を試してみたという話や、特定分野で現在も稼働し続けているWindowsXPマシンに関するセキュリティ上の懸念に関する話がありました。この勉強会はセキュリティ関連の発表も多く、自分のセキュリティに関する知識・認識のアップデートに役立ちます。

次回は6月の開催予定とのことで、興味を持たれた方はぜひ参加してみてください。

「第4回 エンジニアのためのプレゼン技術研究会」の参加メモ

第4回 エンジニアのためのプレゼン技術研究会「みんなの自由研究発表」と「前佛さんのスライドの作り方」に参加してきました。

プレゼン用の図を自動生成する話

今回のテーマは「みんなの自由研究発表」で、各人の自由研究の成果を持ち時間5分で発表するというものでした。自分も「プレゼン用の図を自動生成する話」というタイトルで発表を行いました。

Webブラウザ上で動作するmermaidAPI.jsというJavaScriptライブラリがあり、これを利用して簡単なテキストから動的に図を生成する、というネタでの発表内容でした。

サンプルプログラムは以下のURLから試してみることができます。

mermaidAPI.jsのサンプルプログラム使用手順

発表時間が5分ということもあり、当日の発表ではデモを行えなかったので、上記のサンプルプログラムを使用した簡単な作業フローを紹介します。

まずはサンプルプログラムでmermaidの記法に沿ったテキストを入力し、図を作成します。図は自動で生成(レンダリング)されます。

例として、アニメ「プリパラ」の人物相関図を作成してみます。以下のような感じですね。

f:id:furandon_pig:20151012174646p:plain

mermaidAPI.jsはSVGを生成するので、Inkscape等のSVGが編集可能なツールで図の修正や微調整が行えます。ただし、mermaidAPI.jsが生成するSVGは、テキスト表示用に独自のSVGタグを使っていたりするので、そのままではInkscapeで表示できないものがあります。上記サンプルプログラムではInkscapeで表示できるよう、生成されたSVGを一部修正しています。

f:id:furandon_pig:20151012174715p:plain

Inkscapeで表示すると以下のような感じになります。図中の矢印は直線で構成されていますが、パスの中間点を削除すると滑らかな曲線になるので、ここは手動で中間点を削除します。他にもパスの端点を矢印の形に変更したりしています。

f:id:furandon_pig:20151012234535p:plain

あとはEPS形式で保存するだけなのですが、その前に画像サイズを調整します。[ファイル]-[ドキュメントのプロパティ(D)...]を選択し、「ページ」タブの中にある「ページサイズを描画全体または選択オブジェクトに合わせる(R)」ボタンをクリックします。

f:id:furandon_pig:20151012235420p:plain

ESPで保存した画像は、KeynotePowerPointなどに挿入して利用します。Keynoteの場合は、メニューから[挿入]-[選択...]でEPSファイルを挿入できます。

f:id:furandon_pig:20151012174725p:plain

まとめ

第4回 エンジニアのためのプレゼン技術研究会で発表した内容の補足説明をまとめてみました。プレゼン技術に関するノウハウはスライドの作り方・構成方法、発表時のハマり所等、以外と範囲が広いです。今後もプレゼン技術研究会でノウハウを集めてゆければと思います。