コグノスケ


link 未来から過去へ表示(*)  link 過去から未来へ表示

link もっと前
2022年5月27日 >>> 2022年5月14日
link もっと後

2022年5月27日

PulseAudioで簡易リモート再生

目次: ALSA

遠くの部屋にあるPCで再生した音声を手元のスピーカーで聞きたい場合、スピーカーの線を延々と伸ばすよりリモート再生したほうが楽です。

リモート再生の方法はいくつかありますが、最近のLinuxディストリビューションであれば大抵はPulseAudioがインストールされていると思うので、PulseAudioのTCP送信機能を使うのが楽でしょう。

Cookieの設定

クライアントとサーバーが同じ内容のCookie(~/.config/pulse/cookieにある)を持っていないと、下記のようにAccess deniedといわれて接続できません。

クライアントとサーバーでCookieの内容が異なるときのエラー
$ PULSE_SERVER=192.168.1.10 speaker-test -D pulse

speaker-test 1.2.9

Playback device is pulse
Stream parameters are 48000Hz, S16_LE, 1 channels
Using 16 octaves of pink noise
ALSA lib pulse.c:242:(pulse_connect) PulseAudio: Unable to connect: Access denied

Playback open error: -111,Connection refused

クライアントにCookieファイルをコピーできない場合は、module-native-protocol-tcpにauth-anonymous=1を渡すと良いそうです。

サーバー側

サーバー側は音声を受け取ってスピーカーなどに送る役目を果たします。私はスピーカーの横にRaspberry Piを置いてサーバーにしています。PulseAudioの設定は簡単で、

PulseAudioの設定ファイルを変更
# vi /etc/pulse/default.pa 

load-module module-native-protocol-tcp

既にPulseAudioが起動している場合があるので、一度終了させます。

PulseAudioの終了、起動
$ pacmd

Welcome to PulseAudio 12.2! Use "help" for usage information.

>>> exit

# PulseAudioの再起動をします。

$ pulseaudio -D

PulseAudioの設定テストを行う場合は-Dなし(フォアグラウンド実行)すると良いです。Crtl-Cで終了できますので、起動&終了が素早くできて楽です。

クライアント側

クライアント側はMP3などをデコードし、音声をサーバーに送る役目を果たします。使い方は環境変数PULSE_SERVERを指定して再生するだけです。

クライアント側で音声再生
$ export PULSE_SERVER=192.168.1.10    # ★★PulseAudioサーバー側のIPアドレス★★
$ mplayer --no-video test.mp3

本当はmodule-zeroconf-discoverを正しく設定すれば環境変数をいちいち設定する必要はなく、PulseAudioの設定GUIから出力先の一つとして選択できるようになるはずです。が、どうも私の環境だとうまく動いてくれなくて挫折しました……。

編集者:すずき(2023/11/30 16:16)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年5月26日

glibcのスレッドとスタック

目次: C言語とlibc

誰も興味ないglibcの話シリーズ、スレッドのスタックはどうやって確保するのか?を追います。

ソースコードはglibc-2.35を見ています。pthread_create() の実体はいくつかありますが、2.34以降ならば __pthread_create_2_1() という関数が実体です。

pthread_createの実体

// glibc/nptl/pthread_create.c

versioned_symbol (libc, __pthread_create_2_1, pthread_create, GLIBC_2_34);
libc_hidden_ver (__pthread_create_2_1, __pthread_create)
#ifndef SHARED
strong_alias (__pthread_create_2_1, __pthread_create)
#endif

主要な関数としては、スタックを確保するallocate_stack() とclone() を呼ぶcreate_thread() です。スレッド属性も見てますが、今回は特に使わないので無視します。

スレッド作成に関わる関数の呼び出し関係
__pthread_create_2_1
  allocate_stack
    get_cached_stack
  create_thread

スレッドのスタックは2通りの確保方法があります。1つはキャッシュ、もう1つはmmap() です。

スレッドのスタックを確保する処理

// glibc/nptl/pthread_create.c

static int
allocate_stack (const struct pthread_attr *attr, struct pthread **pdp,
		void **stack, size_t *stacksize)
{

  //...

      /* Try to get a stack from the cache.  */
      reqsize = size;
      pd = get_cached_stack (&size, &mem);
      if (pd == NULL)    //★★キャッシュがなければこのif文が成立してmmapでメモリ確保★★
	{
	  /* If a guard page is required, avoid committing memory by first
	     allocate with PROT_NONE and then reserve with required permission
	     excluding the guard page.  */
	  mem = __mmap (NULL, size, (guardsize == 0) ? prot : PROT_NONE,
			MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);

  //...

    retval = create_thread (pd, iattr, &stopped_start, stackaddr,
			    stacksize, &thread_ran);

  //...

このget_cached_stack() がNULLを返す=失敗=キャッシュからスタックを確保できなかった、という意味です。確保できない場合はmmap() を呼んでカーネルから匿名ページを確保し、スタック領域として使います。

キャッシュに追加する人は誰?

キャッシュからスタックを確保できる場合は何か?というと、既に終了したスレッドのスタック領域がキャッシュにある場合です。スレッドの回収pthread_join() が終わった後のスレッドのスタックにアクセスしてはいけません。つまり誰もアクセスしない領域です。

スタック領域をカーネルに返しても良いですが、カーネルからメモリを確保したり解放するのは一般的に遅い処理のため、別のスレッドのスタックとして再利用してカーネルからのメモリ確保&解放の回数を減らし、効率を上げる仕組みと思われます。

まずは読み出す側であるget_cached_stack() 関数のコードから見ます。ちなみにコード内に頻出するtcbという単語はThread Controll Blockの略だそうです。

キャッシュからスタックを確保する処理

// glibc/nptl/allocatestack.c

static struct pthread *
get_cached_stack (size_t *sizep, void **memp)
{
  size_t size = *sizep;
  struct pthread *result = NULL;
  list_t *entry;

  lll_lock (GL (dl_stack_cache_lock), LLL_PRIVATE);

  /* Search the cache for a matching entry.  We search for the
     smallest stack which has at least the required size.  Note that
     in normal situations the size of all allocated stacks is the
     same.  As the very least there are only a few different sizes.
     Therefore this loop will exit early most of the time with an
     exact match.  */
  list_for_each (entry, &GL (dl_stack_cache))    //★★キャッシュのリストを全部調べる★★
    {
      struct pthread *curr;

      curr = list_entry (entry, struct pthread, list);
      if (__nptl_stack_in_use (curr) && curr->stackblock_size >= size)
	{
	  if (curr->stackblock_size == size)    //★★一致するサイズのスタックがあれば使う★★
	    {
	      result = curr;
	      break;
	    }

	  if (result == NULL
	      || result->stackblock_size > curr->stackblock_size)
	    result = curr;
	}
    }

  //...

カギを握るのはdl_stack_cacheというスタック領域をキャッシュするリストのようです。先程も言いましたが、このリストに要素が追加されるタイミングの1つはpthread_join() です。pthread_join() からコードを追います。

pthread_join() からスタックをキャッシュに追加する処理まで

// glibc/nptl/pthread_join.c

int
___pthread_join (pthread_t threadid, void **thread_return)    //★★pthread_join() の実体★★
{
  return __pthread_clockjoin_ex (threadid, thread_return, 0 /* Ignored */,
				 NULL, true);
}
versioned_symbol (libc, ___pthread_join, pthread_join, GLIBC_2_34);


// glibc/nptl/pthread_join_common.c

int
__pthread_clockjoin_ex (pthread_t threadid, void **thread_return,
                        clockid_t clockid,
                        const struct __timespec64 *abstime, bool block)
{
  struct pthread *pd = (struct pthread *) threadid;

  //...

  void *pd_result = pd->result;
  if (__glibc_likely (result == 0))
    {
      /* We mark the thread as terminated and as joined.  */
      pd->tid = -1;

      /* Store the return value if the caller is interested.  */
      if (thread_return != NULL)
	*thread_return = pd_result;

      /* Free the TCB.  */
      __nptl_free_tcb (pd);    //★★これ★★
    }
  else
    pd->joinid = NULL;

  //...


// glibc/nptl/nptl_free_tcb.c

void
__nptl_free_tcb (struct pthread *pd)
{
  /* The thread is exiting now.  */
  if (atomic_bit_test_set (&pd->cancelhandling, TERMINATED_BIT) == 0)
    {
      /* Free TPP data.  */
      if (pd->tpp != NULL)    //★余談TPP = Thread Priority Protectだそうです★
        {
          struct priority_protection_data *tpp = pd->tpp;

          pd->tpp = NULL;
          free (tpp);
        }

      /* Queue the stack memory block for reuse and exit the process.  The
         kernel will signal via writing to the address returned by
         QUEUE-STACK when the stack is available.  */
      __nptl_deallocate_stack (pd);    //★★これ★★
    }
}
libc_hidden_def (__nptl_free_tcb)


// glibc/nptl/nptl-stack.c

void
__nptl_deallocate_stack (struct pthread *pd)
{
  lll_lock (GL (dl_stack_cache_lock), LLL_PRIVATE);

  /* Remove the thread from the list of threads with user defined
     stacks.  */
  __nptl_stack_list_del (&pd->list);

  /* Not much to do.  Just free the mmap()ed memory.  Note that we do
     not reset the 'used' flag in the 'tid' field.  This is done by
     the kernel.  If no thread has been created yet this field is
     still zero.  */
  if (__glibc_likely (! pd->user_stack))
    (void) queue_stack (pd);    //★★これ★★
  else
    /* Free the memory associated with the ELF TLS.  */
    _dl_deallocate_tls (TLS_TPADJ (pd), false);

  lll_unlock (GL (dl_stack_cache_lock), LLL_PRIVATE);
}
libc_hidden_def (__nptl_deallocate_stack)


/* Add a stack frame which is not used anymore to the stack.  Must be
   called with the cache lock held.  */
static inline void
__attribute ((always_inline))
queue_stack (struct pthread *stack)
{
  /* We unconditionally add the stack to the list.  The memory may
     still be in use but it will not be reused until the kernel marks
     the stack as not used anymore.  */
  __nptl_stack_list_add (&stack->list, &GL (dl_stack_cache));  //★★キャッシュのリストに追加★★

  GL (dl_stack_cache_actsize) += stack->stackblock_size;
  if (__glibc_unlikely (GL (dl_stack_cache_actsize)
			> __nptl_stack_cache_maxsize))
    __nptl_free_stacks (__nptl_stack_cache_maxsize);
}

やっとリストdl_stack_cacheにスタック領域を追加している場所まで来ました。もっとあっさりかと思いましたが、意外と呼び出しが深かったです……。

編集者:すずき(2022/05/27 20:39)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年5月23日

ほとんど見かけないSI接頭辞デカ(da)

何かの量を表すときは数字+単位(例: 100m)で表します。余りにも桁が多くなり見づらい場合は適切な接頭辞を付けて数字の桁を減らして表すことが多いです(例: 100000m → 100km)。接頭辞はSI(国際単位系)で定義されており、1/1000を表すミリ(m)や1000倍を表すキロ(k)などがあります。これらは良く見かける接頭辞だと思います。

しかしSI接頭辞として定義されているものの、あまり使われない接頭辞もあります。顕著な物はデシ(d)、ヘクト(h)やデカ(da)辺りでしょう。デシとヘクトは少ないながらも見かけますが、デカは使われているところを見たことがありません。

ルールとしてはSI単位であれば、どのSI接頭辞を付けても間違いではない(ヘクトメートルhmも正しい)ですが、非SI単位はSI接頭辞を付けてはいけない場合があります。良く見かける組み合わせを表にしてみました。

接頭辞 m g PaHzB L a
k(x1000)
h(x100)
da(x10)
d(x1/10)
c(x1/100)
m(x1/1000)

各単位の簡単な解説です。

  • m: メートル、長さのSI基本単位
  • g: グラム、質量のSI基本単位(正確にはkgがSI基本単位)
  • Pa: パスカル、圧力のSI組立単位
  • Hz: ヘルツ、周波数のSI組立単位
  • B: ベル、比を表す単位
  • L: リットル、体積の非SI単位、1000cm^3
  • a: アール、面積の非SI単位(aは廃止され、haのみが残っている)、100m^2

デカを良く使う単位があれば、是非お目に掛かりたいところです……。

編集者:すずき(2022/05/25 00:25)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年5月20日

alsa-lib dmixのバグを直した

目次: ALSA

先日送ったalsa-libへのパッチ(2022年4月29日の日記参照)がマージされました(該当するコミットへのリンク)。3週間くらい何も反応が無かったので、送り先を間違ったかな……?と思い始めたところでした。やー良かった良かった。

バグの発見(2014年7月9日の日記参照)から直るまでに8年も空きました。ALSAのような有名なOSSだと利用者数も半端ないので、バグを年単位で放っておくと他の人が同じバグに気づいて直すことが多いです。ところが、このバグは割と発生条件が変わっているのもあり、誰もバグに気づかなかったか、わざわざ直す価値を感じなかったのでしょう。有名OSSでは割と珍しいケースですよね。

編集者:すずき(2022/05/23 00:34)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年5月18日

BIGLOBE光からの勧誘

目次: プロバイダ

携帯に突然BIGLOBE光から電話が掛かってきて、ドコモ光から切り替えないか?と勧誘されました。KDDIはどこから私の電話番号と、ドコモ光を契約していることを知ったのでしょうか……?

勧誘の人は1,000円/月くらい安くなるはず、今なら工事費を無料で切り替えられる、キャッシュバックの分だけ得、とまくし立ててきます。しかし過去に電話勧誘で契約して良かったことがない(ドコモ光に変えた時とか)ので、契約しませんでした。

料金を確認すると今使っているドコモ光(タイプA)は4,400円/月、BIGLOBE光は4,378円/月で、ほとんど変わりません。しかもBIGLOBE光は3年縛りで、解約の機会がさらに限られます(違約金は11,900円も取られる)。ドコモ光の2年縛りだって最悪なのに3年縛り……悪化させてどうするんでしょう。

適当ばっかり言いやがって、これだから電話勧誘は嫌いなんだ。

編集者:すずき(2022/05/20 00:56)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年5月16日

日本語がおかしいフィッシング詐欺メール

海外から日本語がおかしいスパムやフィッシング詐欺のメールが来ることは多いですが、今回来たメールは桁違いに単語がおかしいです。


日本語がおかしいフィッシング詐欺メール(テキスト表示)

一例を挙げれば、

  • Amazこれをon安全センター
  • 第三ほっとし者
  • 自かりの動的に
  • 設定されがりました
  • ご正常的な仕様に影ンが響
  • シスなたにテム
  • ユーランザーいませ管理いでくセンあなたター
  • 発いとき行元
  • 株えてす式会社
  • Ammsdfazon!?

わざとやっているのではないか?と思うほどにおかしいです。

HTMLだとどうなる?

メールヘッダを見るとContent-Typeがtext/htmlとなっていたので、これはもしかしてHTML表示の場合のみまともに見えるタイプなのでは?と疑って、普段使っているテキスト表示から、HTML表示に変更したところ、


日本語がおかしいフィッシング詐欺メール(HTML表示)

割とまともに表示されました。日本語としてはイマイチですが、完全におかしい単語はなりを潜めています。

テキスト表示の際に多数出てきたおかしな単語の役割もわかりましたね。表示されないようにした意味の無い文字を紛れ込ませ、テキストしか見ないメールクライアントのスパムフィルターに引っかかる事態を回避していると思われます。うまくやっているつもりなんでしょうけど、普段からHTML表示を無効にしている人には、意味の無い文字が全て見えて逆に不審度がMaxになる諸刃の剣です。

余計なことばかり工夫する暇があるなら、その頭をもっと役に立つことに使えば良いのにね……。

編集者:すずき(2022/05/17 22:52)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年5月15日

携帯電話事業者の栄枯盛衰

楽天モバイルが有料化するというニュースが話題になっていました。無料攻勢を続けていましたが、シェアは2%程度でかなり苦戦しているそうです。

携帯電話と言えば今も昔もドコモが強いイメージですが、果たしてその認識は合っているのでしょうか?電気通信事業者協会のデータを元に1996年〜2014年までの契約者数をグラフにしてみました(グラフとまとめたデータはGoogleスプレッドシートにしておきました)。ウィルコムとアステルのデータはなぜか1996/06からしか取れないため、グラフがやや変になっています。ご了承ください。


携帯電話事業者ごとの契約者数

見事にドコモが強いです。ドコモが絶対王者なのはずっと変わらないんですが、

  • 〜2001: ドコモ爆売れ時代
  • 〜2007: auの追撃時代
  • 〜2014: ソフトバンクの追撃時代

という具合でしょうか。

たしか国際電信電話(KDD)、第二電電(DDI)、日本移動通信(IDO)の三社合併でKDDIとなったのが2000年で、ブランドスローガンau by KDDIを言い始めたのが2000年か2001年だった気がします。KDDIがドコモを撃ち落とす覚悟の表れだったのかもしれません。

ソフトバンクに目を向けると、ソフトバンクがVodafoneを買収したのが2006年で、ソフトバンクの猛追はそこから始まったんだろうな〜などと想像するとなかなか面白いグラフですね。

編集者:すずき(2022/05/20 04:40)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



2022年5月14日

スピードシューティングでガスガンの有効活用

目次: 射的

新たな趣味でスピードシューティングを始めました。いくつか大会があるそうですが、私が通い始めたTARGET-1というお店(サイトへのリンク)では「JTSAアンリミテッド」という大会(サイトへのリンク)のルールを使っています。5月末にアンリミテッドの大会があるそうで、大会が終わった6月からはリミテッドという大会(サイトへのリンク)のルールにするとも言っていました。

  • 全5コース
  • 1コースあたり5回の試技(上位4回のタイムを採用)
  • 1回あたり5枚の鉄板を撃つ

全コースの合計タイムがスコアとなり(スコアが少ない=早い方が良い成績)ます。銃によりスピードシューティング向き、不向き(※)はあるものの、基本的には好きな銃+ホルスターで参加して構わないです。

個人競技ですから、タイムが遅くても早くても特に誰も迷惑しないのです。個人競技万歳。

(※)いただいたアドバイスによれば、

  • 不向き: ベレッタ、SIGのような初弾ダブルアクション
  • 上級者: M1911のようなコック&ロックのシングルアクション
  • 初心者: グロックのような(ほぼ)シングルアクション

とのこと。

メモ: 技術系の話はFacebookから転記しておくことにした。いくつか追記。

編集者:すずき(2022/05/16 17:35)

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link もっと前
2022年5月27日 >>> 2022年5月14日
link もっと後

管理用メニュー

link 記事を新規作成

<2022>
<<<05>>>
1234567
891011121314
15161718192021
22232425262728
293031----

最近のコメント5件

  • link 21年3月13日
    すずきさん (03/05 15:13)
    「あー、このプログラムがまずいんですね。ご...」
  • link 21年3月13日
    emkさん (03/05 12:44)
    「キャストでvolatileを外してアクセ...」
  • link 24年1月24日
    すずきさん (02/19 18:37)
    「簡単にできる方法はPowerShellの...」
  • link 24年1月24日
    KKKさん (02/19 02:30)
    「追伸です。\nネットで調べたらマイクロソ...」
  • link 24年1月24日
    KKKさん (02/19 02:25)
    「私もエラーで困ってます\n手動での回復パ...」

最近の記事3件

  • link 24年3月25日
    すずき (03/26 03:20)
    「[Might and Magic Book One TASのその後] 目次: Might and Magicファミコン版以前(...」
  • link 21年10月4日
    すずき (03/26 03:14)
    「[Might and Magicファミコン版 - まとめリンク] 目次: Might and Magicファミコン版TASに挑...」
  • link 24年3月19日
    すずき (03/20 02:52)
    「[モジュラージャックの規格] 古くは電話線で、今だとEthernetで良く見かけるモジュラージャックというコネクタとレセプタク...」
link もっとみる

こんてんつ

open/close wiki
open/close Linux JM
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 2018年
open/close 2019年
open/close 2020年
open/close 2021年
open/close 2022年
open/close 2023年
open/close 2024年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報

合計:  counter total
本日:  counter today

link About www.katsuster.net
RDFファイル RSS 1.0

最終更新: 03/26 03:20