Panagiotis Christopoulos Charitos 8 лет назад
Родитель
Сommit
7634040eba

+ 2 - 0
src/anki/Util.h

@@ -32,6 +32,8 @@
 #include <anki/util/Thread.h>
 #include <anki/util/ThreadPool.h>
 #include <anki/util/Visitor.h>
+#include <anki/util/INotify.h>
+#include <anki/util/SparseArray.h>
 
 /// @defgroup util Utilities (like STL)
 

+ 6 - 0
src/anki/util/CMakeLists.txt

@@ -6,4 +6,10 @@ else()
 	set(ANKI_UTIL_SOURCES ${ANKI_UTIL_SOURCES} HighRezTimerWindows.cpp FilesystemWindows.cpp ThreadWindows.cpp)
 endif()
 
+if(LINUX)
+	set(ANKI_UTIL_SOURCES ${ANKI_UTIL_SOURCES} INotifyLinux.cpp)
+elseif(WINDOWS)
+	set(ANKI_UTIL_SOURCES ${ANKI_UTIL_SOURCES} INotifyWindows.cpp)
+endif()
+
 add_library(ankiutil ${ANKI_UTIL_SOURCES})

+ 58 - 0
src/anki/util/INotify.h

@@ -0,0 +1,58 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#pragma once
+
+#include <anki/util/String.h>
+
+namespace anki
+{
+
+/// @addtogroup util_file
+/// @{
+
+/// A wrapper on top of inotify. Check for filesystem updates.
+class INotify
+{
+public:
+	INotify() = default;
+
+	// Non-copyable
+	INotify(const INotify&) = delete;
+
+	~INotify()
+	{
+		destroyInternal();
+		m_path.destroy(m_alloc);
+	}
+
+	// Non-copyable
+	INotify& operator=(const INotify&) = delete;
+
+	/// @param path Path to file or directory.
+	ANKI_USE_RESULT Error init(GenericMemoryPoolAllocator<U8> alloc, CString path)
+	{
+		m_alloc = alloc;
+		m_path.create(alloc, path);
+		return initInternal();
+	}
+
+	/// Check if the file was modified in any way.
+	ANKI_USE_RESULT Error pollEvents(Bool& modified);
+
+private:
+	GenericMemoryPoolAllocator<U8> m_alloc;
+	String m_path;
+#if ANKI_OS == ANKI_OS_LINUX
+	int m_fd = -1;
+	int m_watch = -1;
+#endif
+
+	void destroyInternal();
+	ANKI_USE_RESULT Error initInternal();
+};
+/// @}
+
+} // end namespace anki

+ 130 - 0
src/anki/util/INotifyLinux.cpp

@@ -0,0 +1,130 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/util/INotify.h>
+#include <anki/util/Logger.h>
+#include <sys/inotify.h>
+#include <poll.h>
+#include <unistd.h>
+
+namespace anki
+{
+
+Error INotify::initInternal()
+{
+	ANKI_ASSERT(m_fd < 0 && m_watch < 0);
+
+	Error err = Error::NONE;
+
+	m_fd = inotify_init();
+	if(m_fd < 0)
+	{
+		ANKI_UTIL_LOGE("inotify_init() failed: %s", strerror(errno));
+		err = Error::FUNCTION_FAILED;
+	}
+
+	if(!err)
+	{
+		m_watch = inotify_add_watch(m_fd, &m_path[0], IN_MODIFY | IN_CREATE | IN_DELETE | IN_IGNORED | IN_DELETE_SELF);
+		if(m_watch < 0)
+		{
+			ANKI_UTIL_LOGE("inotify_add_watch() failed: %s", strerror(errno));
+			err = Error::FUNCTION_FAILED;
+		}
+	}
+
+	if(err)
+	{
+		destroyInternal();
+	}
+
+	return err;
+}
+
+void INotify::destroyInternal()
+{
+	if(m_watch >= 0)
+	{
+		int err = inotify_rm_watch(m_fd, m_watch);
+		if(err < 0)
+		{
+			ANKI_UTIL_LOGE("inotify_rm_watch() failed: %s\n", strerror(errno));
+		}
+		m_watch = -1;
+	}
+
+	if(m_fd >= 0)
+	{
+		int err = close(m_fd);
+		if(err < 0)
+		{
+			ANKI_UTIL_LOGE("close() failed: %s\n", strerror(errno));
+		}
+		m_fd = -1;
+	}
+}
+
+Error INotify::pollEvents(Bool& modified)
+{
+	ANKI_ASSERT(m_fd >= 0 && m_watch >= 0);
+
+	Error err = Error::NONE;
+	modified = false;
+
+	while(true)
+	{
+		pollfd pfd = {m_fd, POLLIN, 0};
+		int ret = poll(&pfd, 1, 0);
+
+		if(ret < 0)
+		{
+			ANKI_UTIL_LOGE("poll() failed: %s", strerror(errno));
+			err = Error::FUNCTION_FAILED;
+			break;
+		}
+		else if(ret == 0)
+		{
+			// No events, move on
+			break;
+		}
+		else
+		{
+			// Process the new event
+
+			inotify_event event;
+			int nbytes = read(m_fd, &event, sizeof(event));
+			if(nbytes == sizeof(event))
+			{
+				if(event.mask & IN_IGNORED)
+				{
+					// File was moved or deleted. Some editors on save they delete the file and move another file to
+					// its place. In that case the m_fd and the m_watch need to be re-created.
+
+					m_watch = -1; // Watch descriptor was removed implicitly
+					destroyInternal();
+					err = initInternal();
+					if(err)
+					{
+						break;
+					}
+				}
+				else
+				{
+					modified = true;
+				}
+			}
+			else
+			{
+				ANKI_UTIL_LOGE("read() failed to read the expected size of data");
+				err = Error::FUNCTION_FAILED;
+				break;
+			}
+		}
+	}
+
+	return err;
+}
+
+} // end namespace anki

+ 29 - 0
src/anki/util/INotifyWindows.cpp

@@ -0,0 +1,29 @@
+// Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+// All rights reserved.
+// Code licensed under the BSD License.
+// http://www.anki3d.org/LICENSE
+
+#include <anki/util/INotify.h>
+
+namespace anki
+{
+
+Error INotify::initInternal()
+{
+	// TODO
+	return Error::NONE;
+}
+
+void INotify::destroyInternal()
+{
+	// TODO
+}
+
+Error INotify::pollEvents(Bool& modified)
+{
+	// TODO
+	modified = false;
+	return Error::NONE;
+}
+
+} // end namespace anki