Skip to content

Commit 0f49a1b

Browse files
committed
[重构macOS目录监控实现]:macOS目录监控实现优化及事件标志解析修复
- 重构事件标志处理逻辑: 将eventFlagsToString改为拼接所有匹配的事件标志,并增加原始值日志输出 - 改用GCD队列管理事件流: 使用FSEventStreamSetDispatchQueue替代CFRunLoop调度机制,提升代码健壮性 - 优化线程管理机制: 移除独立监控线程实现,通过dispatch_queue自动管理事件处理线程 - 完善资源释放流程: 在事件流创建失败时及时释放CF对象,避免内存泄漏 - 增强状态跟踪可靠性: 使用原子变量m_isRunning替代普通bool类型,确保多线程状态同步 - 修正日志输出格式: 修复路径输出缺少空格的拼写问题,提升日志可读性 - 调整事件流参数配置: 将事件延迟间隔从3秒改为立即响应,提升监控实时性
1 parent 0aa6320 commit 0f49a1b

File tree

1 file changed

+69
-70
lines changed

1 file changed

+69
-70
lines changed

MonitorDir/monitordir_mac.cc

Lines changed: 69 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -3,83 +3,90 @@
33
#include <CoreServices/CoreServices.h>
44

55
#include <iostream>
6-
#include <thread>
76

87
std::string eventFlagsToString(FSEventStreamEventFlags eventFlags)
98
{
9+
std::cout << "FSEventStreamEventFlags: " << std::to_string(eventFlags) << std::endl;
10+
11+
std::string text;
1012
if ((eventFlags & kFSEventStreamEventFlagNone) != 0U) {
11-
return "None: ";
13+
text += "None";
1214
}
1315
if ((eventFlags & kFSEventStreamEventFlagMustScanSubDirs) != 0U) {
14-
return "MustScanSubDirs: ";
16+
text += "MustScanSubDirs ";
1517
}
1618
if ((eventFlags & kFSEventStreamEventFlagUserDropped) != 0U) {
17-
return "UserDropped: ";
19+
text += "UserDropped ";
1820
}
1921
if ((eventFlags & kFSEventStreamEventFlagKernelDropped) != 0U) {
20-
return "KernelDropped: ";
22+
text += "KernelDropped ";
2123
}
2224
if ((eventFlags & kFSEventStreamEventFlagEventIdsWrapped) != 0U) {
23-
return "EventIdsWrapped: ";
25+
text += "EventIdsWrapped ";
2426
}
2527
if ((eventFlags & kFSEventStreamEventFlagHistoryDone) != 0U) {
26-
return "HistoryDone: ";
28+
text += "HistoryDone ";
2729
}
2830
if ((eventFlags & kFSEventStreamEventFlagRootChanged) != 0U) {
29-
return "RootChanged: ";
31+
text += "RootChanged ";
3032
}
3133
if ((eventFlags & kFSEventStreamEventFlagMount) != 0U) {
32-
return "Mount: ";
34+
text += "Mount ";
3335
}
3436
if ((eventFlags & kFSEventStreamEventFlagUnmount) != 0U) {
35-
return "Unmount: ";
37+
text += "Unmount ";
3638
}
3739
if ((eventFlags & kFSEventStreamEventFlagItemCreated) != 0U) {
38-
return "Created: ";
40+
text += "Created ";
3941
}
4042
if ((eventFlags & kFSEventStreamEventFlagItemRemoved) != 0U) {
41-
return "Removed: ";
43+
text += "Removed ";
4244
}
4345
if ((eventFlags & kFSEventStreamEventFlagItemInodeMetaMod) != 0U) {
44-
return "InodeMetaMod: ";
46+
text += "InodeMetaMod ";
4547
}
4648
if ((eventFlags & kFSEventStreamEventFlagItemRenamed) != 0U) {
47-
return "Renamed: ";
49+
text += "Renamed ";
4850
}
4951
if ((eventFlags & kFSEventStreamEventFlagItemModified) != 0U) {
50-
return "Modified: ";
52+
text += "Modified ";
5153
}
5254
if ((eventFlags & kFSEventStreamEventFlagItemFinderInfoMod) != 0U) {
53-
return "FinderInfoMod: ";
55+
text += "FinderInfoMod ";
5456
}
5557
if ((eventFlags & kFSEventStreamEventFlagItemChangeOwner) != 0U) {
56-
return "ChangeOwner: ";
58+
text += "ChangeOwner ";
5759
}
5860
if ((eventFlags & kFSEventStreamEventFlagItemXattrMod) != 0U) {
59-
return "XattrMod: ";
61+
text += "XattrMod ";
6062
}
6163
if ((eventFlags & kFSEventStreamEventFlagItemIsFile) != 0U) {
62-
return "IsFile: ";
64+
text += "IsFile ";
6365
}
6466
if ((eventFlags & kFSEventStreamEventFlagItemIsDir) != 0U) {
65-
return "IsDir: ";
67+
text += "IsDir ";
6668
}
6769
if ((eventFlags & kFSEventStreamEventFlagItemIsSymlink) != 0U) {
68-
return "IsSymlink: ";
70+
text += "IsSymlink ";
6971
}
7072
if ((eventFlags & kFSEventStreamEventFlagOwnEvent) != 0U) {
71-
return "OwnEvent: ";
73+
text += "OwnEvent ";
7274
}
7375
if ((eventFlags & kFSEventStreamEventFlagItemIsHardlink) != 0U) {
74-
return "IsHardlink: ";
76+
text += "IsHardlink ";
7577
}
7678
if ((eventFlags & kFSEventStreamEventFlagItemIsLastHardlink) != 0U) {
77-
return "IsLastHardlink: ";
79+
text += "IsLastHardlink ";
7880
}
7981
if ((eventFlags & kFSEventStreamEventFlagItemCloned) != 0U) {
80-
return "Cloned: ";
82+
text += "Cloned ";
83+
}
84+
if (text.empty()) {
85+
text = "Unknown " + std::to_string(eventFlags) + "";
86+
} else {
87+
text += ": ";
8188
}
82-
return "Unknown " + std::to_string(eventFlags) + ": ";
89+
return text;
8390
}
8491

8592
class MonitorDir::MonitorDirPrivate
@@ -101,7 +108,7 @@ class MonitorDir::MonitorDirPrivate
101108
// auto *monitorDir = static_cast<MonitorDirPrivate *>(clientCallBackInfo);
102109
char **paths = static_cast<char **>(eventPaths);
103110
if (paths == nullptr) {
104-
std::cerr << "Error: paths is null." << std::endl;
111+
std::cerr << "Errorpaths is null." << std::endl;
105112
return;
106113
}
107114
for (size_t i = 0; i < numEvents; ++i) {
@@ -113,54 +120,55 @@ class MonitorDir::MonitorDirPrivate
113120
}
114121
}
115122

116-
void monitor()
123+
bool monitor()
117124
{
118-
std::cout << "addWatch: " << dir << std::endl;
119-
CFStringRef pathToWatch = CFStringCreateWithCString(kCFAllocatorDefault,
120-
dir.c_str(),
121-
kCFStringEncodingUTF8);
122-
CFArrayRef pathsToWatch = CFArrayCreate(kCFAllocatorDefault,
123-
reinterpret_cast<const void **>(&pathToWatch),
124-
1,
125-
nullptr);
125+
std::cout << "addWatch" << dir << std::endl;
126+
auto pathToWatch = CFStringCreateWithCString(kCFAllocatorDefault,
127+
dir.c_str(),
128+
kCFStringEncodingUTF8);
129+
auto pathsToWatch = CFArrayCreate(kCFAllocatorDefault,
130+
reinterpret_cast<const void **>(&pathToWatch),
131+
1,
132+
nullptr);
126133
FSEventStreamContext context{0, this, nullptr, nullptr, nullptr};
127-
FSEventStreamRef stream = FSEventStreamCreate(kCFAllocatorDefault,
128-
monitorCallback,
129-
&context,
130-
pathsToWatch,
131-
kFSEventStreamEventIdSinceNow,
132-
3,
133-
kFSEventStreamCreateFlagFileEvents);
134-
runLoop = CFRunLoopGetCurrent();
135-
FSEventStreamScheduleWithRunLoop(stream, runLoop, kCFRunLoopDefaultMode);
134+
stream = FSEventStreamCreate(kCFAllocatorDefault,
135+
monitorCallback,
136+
&context,
137+
pathsToWatch,
138+
kFSEventStreamEventIdSinceNow,
139+
0.,
140+
kFSEventStreamCreateFlagFileEvents);
141+
if (stream == nullptr) {
142+
std::cerr << "Failed to create FSEventStream" << std::endl;
143+
CFRelease(pathsToWatch);
144+
CFRelease(pathToWatch);
145+
return false;
146+
}
147+
auto queue = dispatch_queue_create(nullptr, nullptr);
148+
FSEventStreamSetDispatchQueue(stream, queue);
136149
FSEventStreamStart(stream);
137-
CFRunLoopRun(); // This will block until the stream is stopped.
138-
FSEventStreamStop(stream);
139-
FSEventStreamInvalidate(stream);
140-
FSEventStreamRelease(stream);
141150
CFRelease(pathsToWatch);
142151
CFRelease(pathToWatch);
152+
return true;
143153
}
144154

145155
void stop()
146156
{
147-
if (nullptr == runLoop) {
157+
if (nullptr == stream) {
148158
return;
149159
}
150-
if (CFRunLoopIsWaiting(runLoop) == 0U) {
151-
CFRunLoopWakeUp(runLoop);
152-
}
153-
CFRunLoopStop(runLoop);
160+
FSEventStreamStop(stream);
161+
FSEventStreamInvalidate(stream);
162+
FSEventStreamRelease(stream);
154163
}
155164

156-
void run() { monitor(); }
165+
bool run() { return monitor(); }
157166

158167
MonitorDir *q_ptr;
159168

160-
CFRunLoopRef runLoop = nullptr;
169+
FSEventStreamRef stream = nullptr;
161170

162171
std::filesystem::path dir;
163-
std::thread monitorThread;
164172
};
165173

166174
MonitorDir::MonitorDir(const std::filesystem::path &dir)
@@ -179,29 +187,20 @@ MonitorDir::~MonitorDir()
179187

180188
bool MonitorDir::start()
181189
{
182-
if (m_isRunning) {
190+
if (m_isRunning.load()) {
183191
std::cerr << "MonitorDir is already running" << std::endl;
184192
return false;
185193
}
186-
187-
m_isRunning.store(true);
188-
d_ptr->monitorThread = std::thread([this] {
189-
d_ptr->run();
190-
m_isRunning.store(false);
191-
});
192-
193-
return true;
194+
m_isRunning.store(d_ptr->run());
195+
return m_isRunning.load();
194196
}
195197

196198
void MonitorDir::stop()
197199
{
198-
if (!m_isRunning) {
200+
if (!m_isRunning.load()) {
199201
std::cerr << "MonitorDir is not running" << std::endl;
200202
return;
201203
}
202204

203205
d_ptr->stop();
204-
if (d_ptr->monitorThread.joinable()) {
205-
d_ptr->monitorThread.join();
206-
}
207206
}

0 commit comments

Comments
 (0)