Linux inotify example

用 intofy 來監控檔案的範例。讓程式在另一個 thread 執行,避免卡住繪圖。
另外為了在程式離開時能夠讓此 thread 離開,所以 read 之前先用 select 確定可讀,避免 block 在 read。

程式碼僅作概念實作用,裡頭一些 utility 函式就不再列出了。程式是根據檔案的內容做相應的動作(emit signal)。

#include <sys/types.h>
#include <sys/inotify.h>

void UdevStatusWatcherThread()
{
    SendDebugString(1, "UdevStatusWatcherThread\n");

    int inotifyfd = inotify_init();
    if (inotifyfd < 0)
    {
        SendDebugString(1, "fail to call inotify_init\n");
        return;
    }

    QString cmd = QString("touch %1").arg(USB_FILE_PATH);
    system(cmd.toStdString().c_str());
    int wd_usb = inotify_add_watch(inotifyfd, USB_FILE_PATH, IN_CLOSE_WRITE);
    int wd_sd = -1;

    if (HmiConf::enableSD())
    {
        cmd = QString("touch %1").arg(SD_FILE_PATH);
        system(cmd.toStdString().c_str());
        wd_sd = inotify_add_watch(inotifyfd, SD_FILE_PATH, IN_CLOSE_WRITE);
    }

    while (!g_exitUdevStatusWatcherThread)
    {
        const int buflen = 32 * (sizeof(struct inotify_event) + NAME_MAX + 1);
        char buf[buflen];

        // wait for an event to occur
        // to avoid blocking call, use select

        fd_set rset;
        timeval timeout = {0};
        FD_SET(inotifyfd, &rset); // 將 winSocket 控制代碼加至集合
        timeout.tv_sec = 0;
        timeout.tv_usec = 100000; // 100ms

        if (select(inotifyfd + 1, &rset, NULL, NULL, &timeout) > 0) // select 成功時回傳 ready 的 handle 數
        {
            int numRead = read(inotifyfd, buf, buflen);
            SendDebugString(1, "inotify read len %d\n", numRead);

            if (numRead > 0)
            {
                for (char *p = buf; p < buf + numRead;)
                {
                    struct inotify_event *event = (struct inotify_event *)p;

                    if (event->mask & IN_CLOSE_WRITE)
                    {
                        if (event->wd == wd_usb)
                        {
                            QString line = readUdevStatus(USB_FILE_PATH);
                            line = line.trimmed();
                            SendDebugString(1, "usb status changed to %s\n", line.toStdString().c_str());

                            if (line == QLatin1String("add"))
                            {
                                emit gApp.view->deviceManager()->sigDeviceAdded(QLatin1String("usb"));
                            }
                            else if (line == QLatin1String("remove"))
                            {
                                emit gApp.view->deviceManager()->sigDeviceRemoved(QLatin1String("usb"));
                            }
                        }
                        else if (event->wd == wd_sd)
                        {
                            QString line = readUdevStatus(SD_FILE_PATH);
                            line = line.trimmed();
                            SendDebugString(1, "sd status changed to %s\n", line.toStdString().c_str());

                            if (line == QLatin1String("add"))
                            {
                                emit gApp.view->deviceManager()->sigDeviceAdded(QLatin1String("sd"));
                            }
                            else if (line == QLatin1String("remove"))
                            {
                                emit gApp.view->deviceManager()->sigDeviceRemoved(QLatin1String("sd"));
                            }
                        }
                    }

                    p += sizeof(struct inotify_event) + event->len;
                }
            }
        }
    }

    inotify_rm_watch(inotifyfd, wd_usb);

    if (wd_sd != -1)
    {
        inotify_rm_watch(inotifyfd, wd_sd);
    }
    close(inotifyfd);
}

留言

熱門文章