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);
}
另外為了在程式離開時能夠讓此 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);
}
留言
張貼留言