Armadilloフォーラム

AWL13 のifupでアプリケーションが一時停止してしまう

fukasawa

2020年8月13日 19時14分

いつもお世話になっております。

Armadillo-640にてAWL13を有効にする`ifup awlan0`とアプリケーションが一時的に停止されてしまいます。
原因・対処方法わかりますでしょうか。

Armadillo-640にAWL13を接続しています。
Linux起動時に非同期でネットワークの起動と自作のアプリケーションを開始しています。
アプリケーションでは主にUART2・UART5とのデータの送受信を行い、標準出力(UART3)に1秒に1回現在の状態をprintしています。

このとき、最初は問題なく動作しますが、1分過ぎたあたりで、AWL13が有効になったせいか10秒ほどアプリケーションが停止しています。

Teratermで記録したログを抜粋して変更したものが以下です。全体を添付します。
1:14~1:26と1:26~1:38の間でフリーズしています。

...
[0 00:01:12.0234] meas, 0057.000, F, F,,,
[0 00:01:13.0234] meas, 0058.000, F, F,,,
[0 00:01:13.0906] No DHCPOFFERS received.
[0 00:01:13.0906] No working leases in persistent database - sleeping.
[0 00:01:14.0234] meas, 0059.000, F, F,,,
[0 00:01:14.0609] [   72.173286] awl13: WID_STATUS CODE=0 (DISCONNECTED)
[0 00:01:14.0625] [   72.178192] awl13: disconnected!
[0 00:01:14.0625] [   72.181637] awl13: WID_STATUS CODE=1 (OK)
[0 00:01:14.0672] [   72.217656] awl13: WID_STATUS CODE=0 (DISCONNECTED)
[0 00:01:14.0672] [   72.222558] awl13: disconnected!
(ここでフリーズ!)
[0 00:01:26.0344] [   83.915912] awl13: WID_STATUS CODE=1 (OK)
[0 00:01:26.0469] meas, 0060.000, F, F,,,
[0 00:01:26.0469] meas, 0061.000, F, F,,,
[0 00:01:26.0469] meas, 0066.000, F, F, 26.01[   83.968653] awl13: WID_STATUS CODE=0 (DISCONNECTED)
[0 00:01:26.0469] [   83.976205] awl13: disconnected!
[0 00:01:26.0469] , 25.99, 26.03, 25.56, 25.52, 25.18, -0.00, 0.87, 0.41, 000, F 
[0 00:01:26.0469] meas, 0067.000, F, F,,,
[0 00:01:26.0469] meas, 0068.000, F, F,,,
[0 00:01:26.0469] meas, 0069.000, F, F,,,
[0 00:01:26.0484] meas, 0070.000, F, F,,,
[0 00:01:26.0484] meas, 0071.000, F, F,,,
(ここでフリーズ!)
[0 00:01:38.0094] [   95.667540] awl13: WID_STATUS CODE=1 (OK)
[0 00:01:38.0219] meas, 0072.000, F, F,,,
[0 00:01:38.0219] meas, 0073.000, F, F,,, 
...

自動起動のサービス(call_script_A640_unit.serviceI)は以下です。

[Unit]
Description = call program daemon
After = systemd-networkd-wait-online.service
 
[Service]
ExecStart = /usr/local/bin/call_program_A640.sh
Restart = no
Type = simple
StandardOutput = tty
 
[Install]
WantedBy = multi-user.target

サービスから呼び出されるスクリプト(call_program_A640.sh)は以下です。

#!/bin/sh
echo start call_program
 
# ネットワーク関連セットアップを非同期で開始しておく
{
    ifup eth0
    ifup awlan0
    # 時刻を取得できたら現在時刻を表示
    echo date
    eval date
} &
 
my_program="/usr/local/bin/myApp"
eval $my_program

/etc/network/interfacesの中身は以下です。

# interfaces(5) file used by ifup(8) and ifdown(8)
 
allow-hotplug eth0
auto lo
iface lo inet loopback
iface eth0 inet dhcp
 
iface awlan0 inet dhcp
        pre-up iwpriv awlan0 set_psk (ぱすわーど)
        pre-up iwpriv awlan0 set_cryptmode WPA2-AES
        pre-up iwconfig awlan0 essid (まいSSID)
        wireless-mode managed
ファイル ファイルの説明
teraterm_起動_640_200813_WLAN自動起動.log
コメント

at_akihito.irie

2020年8月17日 17時33分

入江です。

1点確認させてください。

添付いただいたログを見る限り、お使いのアプリケーションはフリーズ時に出
力が遅れているだけで、データの取得は毎秒行っており欠損はないように見え
ますが、この挙動では問題があるということでしょうか?

> 添付いただいたログを見る限り、お使いのアプリケーションはフリーズ時に出
> 力が遅れているだけで、データの取得は毎秒行っており欠損はないように見え
> ますが、この挙動では問題があるということでしょうか?

はい、欠損は確かにないですし、標準出力への遅れは致命的な問題ではありません。
しかし、このフリーズ中にUART2・UART5との通信もフリーズしてしまっているので、そちらは解決したいです。

いろいろ実験して、わかったことを追記します。

以下のフォーラムを参考にしました。
https://armadillo.atmark-techno.com/forum/armadillo/3345

どうも自動起動のサービス(call_script_A640_unit.serviceI)の中`After=`の欄に記述していたサービス自体が無効状態だったので、有効化しました。

root@armadillo:~# systemctl enable systemd-networkd
root@armadillo:~# systemctl enable systemd-networkd-wait-online

その後再起動すると、ログの内容が代わり、今まで17秒ぐらいでアプリケーションが起動していたのが、2分23秒ほどかかるようにり、起動後直後にも10秒ほどフリーズしてしまいました。

Teratermのログ抜粋

[0 00:00:16.0515] [  OK  ] Started OpenBSD Secure Shell server.
[0 00:00:21.0594] [*     ] A start job is running for Wait for… to be Configured (12s / no limit)[**    ] A start job...
[0 00:01:05.0062] [   61.435828] random: 6 urandom warning(s) missed due to ratelimiting
[0 00:01:05.0094] [ ***  ] A start job is running for Wait for… to be Configured (56s / no limit)[  *** ] A start job...
[0 00:02:11.0640] See 'systemctl status systemd-networkd-wait-online.service' for details.
...
[0 00:02:23.0797] meas, 0001.000, F, F,,,
...
[0 00:02:23.0797] meas, 0008.000, F, F,,,
[0 00:02:35.0453] [  151.831434] awl13: WID_STATUS CODE=1 (OK)
[0 00:02:35.0578] meas, 0009.000, F, F,,,

at_akihito.irie

2020年8月18日 15時44分

入江です。

call_program_A640.sh内の
eval $my_program

eval nice -n -20 $my_program
にして試していただけますか?

#!/bin/sh
echo start call_program
 
# ネットワーク関連セットアップを非同期で開始しておく
{
ifup eth0
ifup awlan0
# 時刻を取得できたら現在時刻を表示
echo date
eval date
} &
 
my_program="/usr/local/bin/myApp"
eval nice -n -20 $my_program #この行を編集

回答ありがとうございます。
いただいたコマンドに変更しました。

systemd-networkdとsystemd-networkd-wait-onlineを無効・有効にした状態の両方を試してみましたが、変更前とあまり差異はなかったようにみえます。

無効状態の場合はアプリケーションが17秒ぐらいで起動して、1:33~1:45と1:47~1:57の間でフリーズしています。

ログ抜粋(無効状態)

[0 00:00:16.0640] meas, 0001.000, F, F,,, 
[0 00:00:16.0640] DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 9
[0 00:00:17.0593] meas, 0002.000, F, F,,,
...
[0 00:01:31.0609] meas, 0076.000, F, F,,,
[0 00:01:31.0906] start up awlan0
[0 00:01:32.0609] meas, 0077.000, F, F,,,
[0 00:01:32.0984] [   91.235215] awl13: WID_STATUS CODE=0 (DISCONNECTED)
[0 00:01:32.0984] [   91.240117] awl13: disconnected!
[0 00:01:32.0984] [   91.243490] awl13: WID_STATUS CODE=1 (OK)
[0 00:01:33.0609] meas, 0078.000, F, F,,,
[0 00:01:33.0687] [   91.937996] awl13: WID_STATUS CODE=0 (DISCONNECTED)
[0 00:01:33.0687] [   91.942902] awl13: disconnected!
[0 00:01:45.0375] [  103.636601] awl13: WID_STATUS CODE=1 (OK)
[0 00:01:45.0468] meas, 0079.000, F, F,,,
...
[0 00:01:47.0593] meas, 0091.000, F, F,,,
[0 00:01:57.0375] [  115.545976] awl13: WID_STATUS CODE=1 (OK)
[0 00:01:57.0375] meas, 0092.000, F, F,,,

有効状態の場合はアプリケーションが2分21秒ぐらいで起動して、2:22~2:34と3:21~3:26の間でフリーズしています。

ログ抜粋(有効状態)

[0 00:02:22.0094] meas, 0008.000, F, F,,,
[0 00:02:22.0360] [  141.154382] awl13: WID_STATUS CODE=0 (DISCONNECTED)
[0 00:02:22.0360] [  141.159286] awl13: disconnected!
[0 00:02:34.0047] [  152.853147] awl13: WID_STATUS CODE=1 (OK)
[0 00:02:34.0157] meas, 0009.000, F, F,,,
...
[0 00:03:21.0094] meas, 0067.000, F, F,,,
[0 00:03:26.0594] meas, 0068.000, F, F,,,

at_akihito.irie

2020年8月19日 13時19分

入江です。

ifupが完了した後にmyAppを実行するようにした場合にも同様にフリーズが
発生するかお試しいただけますでしょうか?

#!/bin/sh
echo start call_program
 
{
ifup eth0
ifup awlan0
 
echo date
eval date
} #この箇所の&を削除する
 
my_program="/usr/local/bin/myApp"
eval nice -n -20 $my_program

> ifupが完了した後にmyAppを実行するようにした場合にも同様にフリーズが
> 発生するかお試しいただけますでしょうか?

実行してみました。
アプリケーションの起動後のフリーズはなくなりました。
systemd-networkdとsystemd-networkd-wait-onlineは無効にしています。

[0 00:00:19.0641] armadillo login: DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 13
[0 00:00:37.0500] DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 13
[0 00:00:50.0500] DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 20
[0 00:01:05.0110] [   63.392378] random: crng init done
[0 00:01:05.0110] [   63.395806] random: 6 urandom warning(s) missed due to ratelimiting
[0 00:01:10.0407] DHCPDISCOVER on eth0 to 255.255.255.255 port 67 interval 3
[0 00:01:13.0313] No DHCPOFFERS received.
...
[0 00:01:13.0844] [   72.119330] awl13: disconnected!
[0 00:01:25.0516] [   83.813311] awl13: WID_STATUS CODE=1 (OK)
[0 00:01:25.0579] [   83.854177] awl13: WID_STATUS CODE=0 (DISCONNECTED)
[0 00:01:25.0579] [   83.859079] awl13: disconnected!
[0 00:01:37.0266] [   95.553063] awl13: WID_STATUS CODE=1 (OK)
...
[0 00:01:37.0672] [   95.944808] awl13: connected!
[0 00:01:44.0047] DHCPREQUEST of 192.168.1.200 on awlan0 to 255.255.255.255 port 67
...
[0 00:01:50.0094] meas, 0001.000, F, F,,,
[0 00:01:51.0110] meas, 0002.000, F, F,,,

ただ、アプリケーションの起動が1:50ほどかかっていますので、できれば30秒ほどに留めたいです。
アプリケーション内でネットワーク機能は使用していますが、起動直後ではないのでネットワークが有効になるのは5分後でも大丈夫です。
ただ、アプリケーションが2秒以上応答がなくなるのは避けたいと考えています。

systemd-networkdとsystemd-networkd-wait-onlineの有効化や/etc/network/interfaceのautoへのeth0の追加、起動スクリプト内のeth0の削除などもやってみましたが、
WLANが有効にならないか起動時間が長くなる結果しか得られませんでした。

at_akihito.irie

2020年8月20日 13時38分

入江です。

myApp内で1秒ごとにデータをprintしているようですが、どのような実装で1秒
待っていますか?
お手数おかけしますが、1秒待っている箇所のソースコードまたは、状況を再現
できる程度のソースコードをいただけると何かがわかるかもしれません。

> myApp内で1秒ごとにデータをprintしているようですが、どのような実装で1秒
待っていますか?

正確に言いますと、1秒待機するという処理はしておらず、以下のようになっています。

2つのUARTの送信/受信が可能になるかを待機(selectを使用)

(必要であれば)UARTに送信

ネットワークの状態をチェック

(あれば)UARTから受信

前回print時から1秒以上経過していたら、print

(ループ)

関連する部分だけ抜き出してアプリケーションを作ってみようとする過程で見つけたのですが、
上記ネットワークの状態をチェック、の部分を削除したら、`ifup`を非同期実行にしてもアプリケーションのフリーズは発生しなくなりました。
該当部分にprint出力を追加した、ソースコードを示します。

/**
 * @brief IPアドレスの取得 (eth0)
 * 
 * @param ip_address 取得したIPアドレス文字列 (eth0)
 * @param size 許容文字列長
 * @return true 取得成功
 * @return false 取得失敗
 */
bool get_current_ip_address(char *ip_address, int size)
{
  printf("get_current_ip_address start");
  int fd = socket(AF_INET, SOCK_DGRAM, 0);
  struct ifreq ifr = {.ifr_addr.sa_family = AF_INET};
  strncpy(ifr.ifr_name, "eth0", IFNAMSIZ - 1);
  printf("get_current_ip_address before ioctl");
  ioctl(fd, SIOCGIFADDR, &ifr);
  printf("get_current_ip_address after ioctl");
  close(fd);
 
  struct in_addr addr_bin = ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr;
  printf("get_current_ip_address checked");
 
  if (addr_bin.s_addr <= 1)
    return false;
 
  snprintf(ip_address, size, "%s", inet_ntoa(addr_bin));
  printf("get_current_ip_address end");
 
  return true;
}

このコードでは"eth0"のIPアドレスを取得しようとして、2文字以上のアドレス値が取得できなければ、ネットワークに接続していない、と判断しています。
ちなみに問題が解決したら、ここに"awlan0"のチェックを追加して、どちらかのIPアドレスが有効ならネットワークに接続しているとみなす方式に変更する予定です。

削除したコードを有効にしますと、"get_current_ip_address before ioctl"の文字が出力された後にフリーズしています。
ですので、`ioctl(fd, SIOCGIFADDR, &ifr)`がフリーズの発生原因のようです。

ArmadilloというよりはC言語の問題のようですが、ここの修正方法わかりますでしょうか。
もし難しければ、ネットワークのチェック部分を別アプリケーションにして、一時ファイル経由などで本アプリケーションにするのがよいでしょうか?

at_akihito.irie

2020年8月21日 15時06分

入江です。

おそらくawlan0のifup中にソケットが中途半端な状態になる期間があり、その
最中にioctl(fd, SIOCGIFADDR, &ifr)を実行しているためブロッキングされて
いるものと見られます。

お客様のご希望の動作を実現するには、仰るとおりネットワーク部分を別アプ
リケーションにするのが良いと思われます。

それであれば、ブロッキングされても一時的に停止するのはネットワーク関連
のプログラムのみとなり、メインの処理を行うプログラムには影響を与えませ
ん。

時間が空いてしまいましたが、無事に解決しましたので、報告させていただきます。
以下の作業の結果、アプリケーションの起動は14秒、非同期でWLANが起動してIPアドレスが確認できるようになり、その際にアプリケーションの動作も問題ありませんでした。

ネットワーク確認部分を別のシェルスクリプトに移動しました。
シェルスクリプトでは`hostname -I`でIPアドレスを取得して、一時ファイル(/run/)に保存します。

その上で、元のC言語のプラグラムはその一時ファイルのみ、定期的に確認するようにしました。

別スクリプト

#!/bin/bash
ip_addrs=
# 1秒おきにIPアドレスを確認して、6文字以上だったら変数に保存する
while [ "${#ip_addrs}" -lt 6 ]
do
# hostname -IでIPアドレスを含む情報を取得して、正規表現でIPアドレスのみにする
    ip_addrs=$(hostname -I | grep -oP '\d+(\.\d+){3}')
    echo ip_addrs = $ip_addrs
    sleep 1
done
 
# 複数のIPアドレスが取得されることがあるので、配列に変換して、最初だけ取得する。
# WiFiと有線LANの場合は有線LANが取得される。
ip_addrs_array=($ip_addrs)
first_ip_addr=${ip_addrs_array[0]}
 
# IPアドレスを一時ファイルに保存する
dir_path="/run/myApp/"
output_path=${dir_path}current_ip_addr.txt
mkdir -p $dir_path
echo $first_ip_addr > $output_path
echo "Current ip address is in "$output_path

呼び出しスクリプトです。
nice のパラメータが-20ですと、ログインが困難だったので-10に変更しました。

#!/bin/sh
echo start call_program
 
# ネットワーク関連セットアップを非同期で開始しておく
{
    ifup eth0
    ifup awlan0
 
    echo date
    eval date
 
    # IPアドレスを取得して、一時ファイルの保存するスクリプト
    find_ip_script="/usr/local/bin/find_ip_addr.sh"
    eval $find_ip_script
} &
 
my_program="/usr/local/bin/myApp"
eval nice -n -10 $my_program