いろいろバックエンドな人の備忘録

CとGoが大好きな人のポエム掲載所

<メモブログ>[未解決]shared_ptr"のポインタ"はどう扱えばいいのだ・・・

TL;DR

  • C++ と mruby
  • shared_ptr"のポインタ"を void* にキャストして保存するときは、vector等のコンテナ要素をポインタにする
  • というか、ベストプラクティスがわからん、そもそもこの設計はよくないかも。

問題

C++ と mruby を使ったプログラムを書いている。

C++の世界では、ほぼ全てのオブジェクトが、shared_ptr<T> で管理されており、例えばライブラリのインターフェイスの引数も const shared_ptr<T>& になっている。 C++の世界だけで完結するならこれでいいのだけれども、mrubyをバインディングしようとすると困った。

このような、グルー言語系のオブジェクトは void* で持たせるようになっていて、mrubyだとDATA_PTRマクロでRubyのオブジェクト型であるmrb_value型を渡すと、void*のポインタが返ってくる。 ここにオリジナルの構造体や値のポインタを入れれば良い。

さて、ここで、 C++shared_ptr<T>のオブジェクトをRuby側にもたせようとする方法は2つ思いつく。

  1. shared_ptr のポインタ を格納する。
  2. shared_ptr<T>#get()で生ポに変換して格納する。

なお、いずれの場合もshared_ptr<T>の参照カウントは無効になる。(これは void* に格納する以上諦めるしかない。)

1.の場合はハマる確率がかなり高い。 色々原因はあるが、まず、 shared_ptr自体のオブジェクトを関数内で生成するタイプならば、その関数を抜けた時点で、格納したオブジェクトは無効になる。 なので、次に使おうとしたときに、アクセス違反になる。(たまに動くけど、それは偶然でコード的にはNG)

void create_object() {
   shared_ptr<HOGE> sptr = std::make_shared<HOGE>();
   DATA_PTR(rb_object) = &sptr
} // ここで sptr 自体は無効になる。C言語をやっていれば当たり前のことではあるが。。。

2.場合は格納は問題ないが、次にC++の世界に戻ってきたときに困る。C++インターフェイスにオブジェクトを渡すときに型が一致しないために、shared_ptr オブジェクトを作ってやる必要がある。 そのときに、参照カウントがすでにある shared_ptr<T> と矛盾してしまう。

void called_by_ruby() {
  HOGE *hoge_ptr = static_cast<HOGE*>( DATA_PTR(rb_object) );
  const shared_ptr hoge_sptr = shared_ptr<HOGE>( hoge_ptr ); //  この shared_ptr の参照カウントはまた 0 になる

  c_plus_plus_function( hoge_sptr  ); //c_plus_plus_function(const shared_ptr<T>& _hoge  );
} 

解決(?)

静的クラスでも、静的変数でもいいので、std::unorderd_mapstd::vector 等を作り、そのインデックスを指してやる。 今回は、std::unorderd_map にし、キーを mrb_value にした。当然ハッシュ関数も必要なので作ってやる。(DATA_PTRのポインタをキーにする)

    struct Mruby_data_value_hash
    {
      size_t operator()(const mrb_value& m_val) const { return reinterpret_cast<size_t>(DATA_PTR(m_val)); }
    };
    struct Mruby_data_value_equal
    {
      bool operator()(const mrb_value& left, const mrb_value& right) const { return DATA_PTR(left) == DATA_PTR(right); }
    };

    std::unorderd_map<mrb_value, std::shared_ptr<HOGE>, Mruby_data_value_hash, Mruby_data_value_equal> sptr;
        
    mrb_value mrb_hoge_init(mrb_state* mrb, mrb_value self) {
       DATA_PTR(self) = (&sptr[self]);  // コンテナのインデックス **のアドレス**
    }

なお、そもそも設計がマズいかもしれない。理屈は Lua等でもおこるはず。いい方法があったら教えてください。

<メモブログ>Paralells Desktop 13 for Mac + USキーボード で日本語入力を Command + Space で使う

Paralells Desktop 13 for Mac + USキーボード で日本語入力を Command + Space で使う方法

環境

症状

  • MacWindows(VM内) もCommand + Space でIMEの切り替え(日本語<ー>英語)を行いたい
  • Macのシステム設定レベルで入力ソースの切り替えを Command + Space に割り当てると、Paralells Desktop アプリケーションのキーバインドが無効(編集不可)になる

解決

手順

vim ~/.config/karabiner/assets/complex_modifications/parallels.json
{
  "title": "Paralells Desktop",
  "rules": [
      {
          "description": "Command to Ctrl",
          "manipulators": [
              {
                  "type": "basic",
                  "from": {
                    "key_code": "left_command",
                      "modifiers": {
                          "optional": [
                              "any"
                          ]
                      }
                  },
                  "to": [
                      {
                        "key_code": "left_control"
                      }
                  ],
                  "conditions": [
                      {
                          "type": "frontmost_application_if",
                          "bundle_identifiers": [
                              "^com\\.parallels\\.desktop\\.console",
                              "^com\\.parallels\\.winapp\\."
                          ]
                      }
                  ]
              }
          ]
      }
  ]
}
  • Karabina Elements の Preferences を開き、Complex Modifications タブ内の Rules を開く。
  • 左下のAdd rule をクリック。

f:id:nrtn:20170909150059p:plain

  • Command to CtrlEnable ボタンをクリックする。

f:id:nrtn:20170909145958p:plain

おわり。

<メモブログ>SoftEther で IPSec サーバを構築した時の Cisco IOS の設定

Ciscoルータをもっているなら、Anyconnect を使ってみてもいいのだけれども、OS標準(Android/Apple iOS含む)でVPNを張れる環境にしたいのでSoftEtherで構築した。

! WAN側は CBAC を使う
ip inspect name CBAC-WAN-OUT tcp
ip inspect name CBAC-WAN-OUT udp router-traffic
ip inspect name CBAC-WAN-OUT icmp router-traffic


! PPPoE を喋るインターフェイス
interface GigabitEthernet0/5
 description to ONU
 no ip address
 duplex auto
 speed auto
 pppoe enable group global
 pppoe-client dial-pool-number 1
!

! 内側のネットワーク
interface Vlan100
 description Inner Network
 ip address 192.168.0.1 255.255.255.0
 ip nat inside
 ip virtual-reassembly in
 ip tcp adjust-mss 1414

! PPPoE (Dialer)
interface Dialer1
 mtu 1454
 ip address negotiated
 ip access-group WAN-IN in
 ip nat outside
 ip virtual-reassembly in
 encapsulation ppp
 ip tcp adjust-mss 1414
 dialer pool 1
 dialer-group 1
 ppp authentication chap callin
 ppp chap hostname <ほげほげ>
 ppp chap password 7 <ふがふが>
 no cdp enable

! NAT 
ip dns server
ip nat inside source list 1 interface Dialer1 overload
ip nat inside source static udp 192.168.0.3 4500 interface Dialer1 4500
ip nat inside source static esp 192.168.0.3 interface Dialer1
ip nat inside source static udp 192.168.0.3 500 interface Dialer1 500
ip route 0.0.0.0 0.0.0.0 Dialer1

! WANインターフェイスのアクセスリスト
ip access-list extended WAN-IN
 permit udp any eq domain any
 permit icmp any any echo-reply
 permit udp any any eq isakmp
 permit udp any any eq non500-isakmp
 permit esp any any
 deny   ip any any log
!

! Dialer と NAPTの設定
dialer-list 1 protocol ip permit
access-list 1 permit 192.168.0.0 0.0.255.255

<日常ネタ>側頸嚢胞に当選した人の日記を公開しました。

ガチャで 0.001 % を引く確率の病気「側頸嚢胞」になったのでその治療までの日記書きました。 読み返してみると、あまりきれいな文章ではないですが、よろしければどうぞ。

sokukeinohou.hateblo.jp