2 // Copyright (c) 2013 Samsung Electronics Co., Ltd.
4 // Licensed under the Apache License, Version 2.0 (the License);
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
8 // http://www.apache.org/licenses/LICENSE-2.0
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
18 * @file FIo_FileEventDispatcher.cpp
19 * @brief This is the implementation file for _FileEventDispatcher class.
22 #include <unique_ptr.h>
24 #include <sys/inotify.h>
28 #include <FBaseInteger.h>
29 #include <FBaseColHashMap.h>
30 #include <FBaseColLinkedList.h>
31 #include <FBaseRtMutex.h>
32 #include <FBaseSysLog.h>
34 #include "FIo_FileEventManagerImpl.h"
35 #include "FIo_FileEventDispatcher.h"
36 #include "FIo_FileEvent.h"
38 #define INOTIFY_BUFFER_LEN (1024*(sizeof(struct inotify_event) + 16))
41 using namespace Tizen::Base;
42 using namespace Tizen::Base::Collection;
43 using namespace Tizen::Base::Runtime;
45 namespace Tizen { namespace Io
48 _FileEventDispatcher* _FileEventDispatcher::__pFileEventDispatcherInstance = null;
50 _FileEventDispatcher::_FileEventDispatcher(void)
59 _FileEventDispatcher::Construct(void)
61 unique_ptr< HashMap > pWatchList(new (std::nothrow) HashMap(SingleObjectDeleter));
62 SysTryReturnResult(NID_IO, pWatchList != null, E_OUT_OF_MEMORY, "The memory is insufficient.");
64 result r = pWatchList->Construct();
65 SysTryReturnResult(NID_IO, !IsFailed(r), r, "Propagating to caller...");
67 __inotifyFd = inotify_init();
68 if (__inotifyFd == -1)
73 SysLogException(NID_IO, E_MAX_EXCEEDED,
74 "The total number of inotify instances has exceeded the maximum limit.");
78 SysLogException(NID_IO, E_MAX_EXCEEDED,
79 "The total number of file descriptors has exceeded the maximum limit.");
83 SysLogException(NID_IO, E_OUT_OF_MEMORY, "The memory is insufficient.");
87 SysLogException(NID_IO, E_SYSTEM, "The method cannot proceed due to a severe system error.");
92 SysLog(NID_IO, "errno: %d (%s)", errno, strerror(errno));
96 GMainContext* pGContext = g_main_context_get_thread_default(); //get own gmain context except default thread
97 if (pGContext == null)
99 pGContext = g_main_context_default(); //get gmain context from me (default)
100 SysTryReturnResult(NID_IO, pGContext != null, E_IO, "Failed to get gmain context.");
103 __pGIOChannel = g_io_channel_unix_new(__inotifyFd); //fd wrapping
104 SysTryCatch(NID_IO, __pGIOChannel != null, r = E_IO, E_IO, "[E_IO] Failed to create gio channel.");
106 __pGSource = g_io_create_watch(__pGIOChannel, (GIOCondition)(G_IO_IN | G_IO_ERR | G_IO_NVAL | G_IO_HUP));
107 SysTryCatch(NID_IO, __pGSource != null, r = E_IO, E_IO, "[E_IO] Failed to create gsource.");
109 g_source_set_callback(__pGSource, (GSourceFunc)OnFileEventOccurred, this, null);
110 g_source_attach(__pGSource, pGContext);
112 __pWatchList = pWatchList.release();
114 SysLog(NID_IO, "inotify fd: %d, channel: 0x%x", __inotifyFd, __pGIOChannel);
118 if (__inotifyFd != -1)
123 if (__pGSource != null)
125 g_source_destroy(__pGSource);
126 g_source_unref(__pGSource);
130 if (__pGIOChannel != null)
132 g_io_channel_unref(__pGIOChannel);
133 __pGIOChannel = null;
139 _FileEventDispatcher::~_FileEventDispatcher(void)
141 if (__inotifyFd != -1)
146 if (__pGSource != null)
148 g_source_destroy(__pGSource);
149 g_source_unref(__pGSource);
152 if (__pGIOChannel != null)
154 g_io_channel_unref(__pGIOChannel);
161 _FileEventDispatcher::InitSingleton(void)
163 _FileEventDispatcher* pInst = new (std::nothrow) _FileEventDispatcher();
164 SysTryReturnVoidResult(NID_IO, pInst != null, E_OUT_OF_MEMORY, "[E_OUT_OF_MEMORY] The memory is insufficient.");
166 result r = pInst->Construct();
167 SysTryCatch(NID_IO, !IsFailed(r), , r, "[%s] Propagating to caller...", GetErrorMessage(r));
169 __pFileEventDispatcherInstance = pInst;
171 std::atexit(DestroySingleton);
179 _FileEventDispatcher::DestroySingleton(void)
181 delete __pFileEventDispatcherInstance;
184 _FileEventDispatcher*
185 _FileEventDispatcher::GetInstance(void)
187 static pthread_once_t onceBlock = PTHREAD_ONCE_INIT;
189 if (__pFileEventDispatcherInstance == null)
192 pthread_once(&onceBlock, InitSingleton);
193 result r = GetLastResult();
196 onceBlock = PTHREAD_ONCE_INIT;
197 SysPropagate(NID_IO, r);
201 return __pFileEventDispatcherInstance;
205 _FileEventDispatcher::SendEvent(void)
207 SysTryReturnResult(NID_IO, __inotifyFd != -1, E_IO, "inotify fd is invalid.");
208 SysLog(NID_IO, "inotify fd: %d", __inotifyFd);
210 char buffer[INOTIFY_BUFFER_LEN + 1] = { 0, };
211 ssize_t length = read(__inotifyFd, buffer, INOTIFY_BUFFER_LEN);
212 SysTryReturnResult(NID_IO, length >= 0 && length < (long)INOTIFY_BUFFER_LEN, E_IO,
213 "Failed to read inotify buffer. errno: %d (%s)", errno, strerror(errno));
215 unsigned long iter = 0;
216 while (iter < static_cast< unsigned long >(length))
218 struct inotify_event* pEvent = (struct inotify_event*)&buffer[iter];
219 SysTryReturnResult(NID_IO, pEvent != null, E_IO, "inotify event info not found.");
221 Integer wd(pEvent->wd);
222 _FileEventInfo* pFileEventInfo = GetFileEventInfo(wd);
223 SysLog(NID_IO, "wd: %d, _FileEventInfo: 0x%x, event mask: 0x%x", pEvent->wd, pFileEventInfo, pEvent->mask);
224 if (pFileEventInfo == null)
226 SysLog(NID_IO, "There is no watch path.");
230 unsigned long event = (unsigned long)pEvent->mask;
231 unsigned int eventId = pEvent->cookie;
236 // TODO: Use full path in Tizen 3.0
237 path.Append(pEvent->name);
241 path.Append(pFileEventInfo->path);
243 // TODO: Resolve path
244 SysLog(NID_IO, "watch path: %ls", path.GetPointer());
246 _FileEventArg* pEventArg= new (std::nothrow) _FileEventArg(event, path, eventId);
247 if (pEventArg != null)
249 _Event* pFileEvent = pFileEventInfo->pFileEventManagerImpl->GetEvent();
250 if (pFileEvent != null)
252 SysLog(NID_IO, "Fire async event, _FileEventManagerImpl: 0x%x, _Event: 0x%x, event mask: 0x%x, eventId: %d",
253 pFileEventInfo->pFileEventManagerImpl, pFileEvent, event, eventId);
254 pFileEvent->FireAsync(*pEventArg);
259 iter += sizeof(struct inotify_event) + pEvent->len;
266 _FileEventDispatcher::OnFileEventOccurred(GIOChannel* source, GIOCondition condition, gpointer data)
268 SysLog(NID_IO, "channel: 0x%x, condition: %d", source, (int)condition);
270 if (condition & G_IO_IN)
272 _FileEventDispatcher* pDispatcher = static_cast< _FileEventDispatcher* >(data);
273 if (pDispatcher != null)
275 pDispatcher->SendEvent();
283 _FileEventDispatcher::AddFileEventInfo(Integer* pWatchDescription, _FileEventInfo* pFileEventInfo)
285 SysLog(NID_IO, "Add event info, wd: %d, _FileEventInfo: 0x%x, _FileEventManagerImpl: 0x%x",
286 pWatchDescription->ToInt(), pFileEventInfo, pFileEventInfo->pFileEventManagerImpl);
287 return __pWatchList->Add(pWatchDescription, pFileEventInfo);
291 _FileEventDispatcher::GetFileEventInfo(Integer& watchDescription)
293 SysLog(NID_IO, "Get event info, wd: %d", watchDescription.ToInt());
294 return dynamic_cast< _FileEventInfo* >(__pWatchList->GetValue(watchDescription));
298 _FileEventDispatcher::RemoveFileEventInfo(Integer& watchDescription)
300 SysLog(NID_IO, "Remove event info, wd: %d", watchDescription.ToInt());
301 __pWatchList->Remove(watchDescription);