diff --git a/Foundation/Foundation_vs71.vcproj b/Foundation/Foundation_vs71.vcproj index 074183f8e..8a579ec64 100644 --- a/Foundation/Foundation_vs71.vcproj +++ b/Foundation/Foundation_vs71.vcproj @@ -574,7 +574,6 @@ - @@ -2132,6 +2131,12 @@ + + + + + + + + + Name="Dynamic"> + Name="Header Files"> + RelativePath=".\include\Poco\DynamicAny.h"> + RelativePath=".\include\Poco\DynamicAnyHolder.h"> + RelativePath=".\include\Poco\DynamicStruct.h"> - - - + RelativePath=".\include\Poco\Dynamic\Pair.h"> + RelativePath=".\include\Poco\Dynamic\Struct.h"> + RelativePath=".\include\Poco\Dynamic\Var.h"> + + + Name="Source Files"> + RelativePath=".\src\Var.cpp"> + RelativePath=".\src\VarHolder.cpp"> diff --git a/Foundation/Foundation_vs80.vcproj b/Foundation/Foundation_vs80.vcproj index 414e179aa..77661b390 100644 --- a/Foundation/Foundation_vs80.vcproj +++ b/Foundation/Foundation_vs80.vcproj @@ -2761,6 +2761,14 @@ RelativePath=".\src\NotificationQueue.cpp" > + + + + + + + + + + + + + + + + NotificationPtr; + typedef Notification::Ptr NotificationPtr; typedef void (C::*Callback)(const NotificationPtr&); NObserver(C& object, Callback method): diff --git a/Foundation/include/Poco/Notification.h b/Foundation/include/Poco/Notification.h index 798dff9ca..b33b906ac 100644 --- a/Foundation/include/Poco/Notification.h +++ b/Foundation/include/Poco/Notification.h @@ -1,7 +1,7 @@ // // Notification.h // -// $Id: //poco/svn/Foundation/include/Poco/Notification.h#2 $ +// $Id: //poco/Main/Foundation/include/Poco/Notification.h#3 $ // // Library: Foundation // Package: Notifications @@ -43,6 +43,7 @@ #include "Poco/Foundation.h" #include "Poco/Mutex.h" #include "Poco/RefCountedObject.h" +#include "Poco/AutoPtr.h" namespace Poco { @@ -56,6 +57,8 @@ class Foundation_API Notification: public RefCountedObject /// template class. { public: + typedef AutoPtr Ptr; + Notification(); /// Creates the notification. diff --git a/Foundation/include/Poco/NotificationCenter.h b/Foundation/include/Poco/NotificationCenter.h index 0bd259e48..208f6ffc8 100644 --- a/Foundation/include/Poco/NotificationCenter.h +++ b/Foundation/include/Poco/NotificationCenter.h @@ -1,7 +1,7 @@ // // NotificationCenter.h // -// $Id: //poco/svn/Foundation/include/Poco/NotificationCenter.h#2 $ +// $Id: //poco/Main/Foundation/include/Poco/NotificationCenter.h#4 $ // // Library: Foundation // Package: Notifications @@ -41,6 +41,7 @@ #include "Poco/Foundation.h" +#include "Poco/Notification.h" #include "Poco/Mutex.h" #include @@ -48,7 +49,6 @@ namespace Poco { -class Notification; class AbstractObserver; @@ -116,7 +116,7 @@ public: void removeObserver(const AbstractObserver& observer); /// Unregisters an observer with the NotificationCenter. - void postNotification(Notification* pNotification); + void postNotification(Notification::Ptr pNotification); /// Posts a notification to the NotificationCenter. /// The NotificationCenter then delivers the notification /// to all interested observers. diff --git a/Foundation/include/Poco/NotificationQueue.h b/Foundation/include/Poco/NotificationQueue.h index 25ba0edf4..97d59d751 100644 --- a/Foundation/include/Poco/NotificationQueue.h +++ b/Foundation/include/Poco/NotificationQueue.h @@ -1,7 +1,7 @@ // // NotificationQueue.h // -// $Id: //poco/svn/Foundation/include/Poco/NotificationQueue.h#2 $ +// $Id: //poco/Main/Foundation/include/Poco/NotificationQueue.h#3 $ // // Library: Foundation // Package: Notifications @@ -41,6 +41,7 @@ #include "Poco/Foundation.h" +#include "Poco/Notification.h" #include "Poco/Mutex.h" #include "Poco/Event.h" #include @@ -49,7 +50,6 @@ namespace Poco { -class Notification; class NotificationCenter; @@ -77,7 +77,7 @@ public: ~NotificationQueue(); /// Destroys the NotificationQueue. - void enqueueNotification(Notification* pNotification); + void enqueueNotification(Notification::Ptr pNotification); /// Enqueues the given notification by adding it to /// the end of the queue (FIFO). /// The queue takes ownership of the notification, thus @@ -85,7 +85,7 @@ public: /// notificationQueue.enqueueNotification(new MyNotification); /// does not result in a memory leak. - void enqueueUrgentNotification(Notification* pNotification); + void enqueueUrgentNotification(Notification::Ptr pNotification); /// Enqueues the given notification by adding it to /// the front of the queue (LIFO). The event therefore gets processed /// before all other events already in the queue. @@ -99,6 +99,10 @@ public: /// Returns 0 (null) if no notification is available. /// The caller gains ownership of the notification and /// is expected to release it when done with it. + /// + /// It is highly recommended that the result is immediately + /// assigned to a Notification::Ptr, to avoid potential + /// memory management issues. Notification* waitDequeueNotification(); /// Dequeues the next pending notification. @@ -108,6 +112,10 @@ public: /// is expected to release it when done with it. /// This method returns 0 (null) if wakeUpWaitingThreads() /// has been called by another thread. + /// + /// It is highly recommended that the result is immediately + /// assigned to a Notification::Ptr, to avoid potential + /// memory management issues. Notification* waitDequeueNotification(long milliseconds); /// Dequeues the next pending notification. @@ -116,6 +124,10 @@ public: /// Returns 0 (null) if no notification is available. /// The caller gains ownership of the notification and /// is expected to release it when done with it. + /// + /// It is highly recommended that the result is immediately + /// assigned to a Notification::Ptr, to avoid potential + /// memory management issues. void dispatch(NotificationCenter& notificationCenter); /// Dispatches all queued notifications to the given @@ -142,14 +154,14 @@ public: /// NotificationQueue. protected: - Notification* dequeueOne(); + Notification::Ptr dequeueOne(); private: - typedef std::deque NfQueue; + typedef std::deque NfQueue; struct WaitInfo { - Notification* pNf; - Event nfAvailable; + Notification::Ptr pNf; + Event nfAvailable; }; typedef std::deque WaitQueue; diff --git a/Foundation/include/Poco/PriorityNotificationQueue.h b/Foundation/include/Poco/PriorityNotificationQueue.h new file mode 100644 index 000000000..5b9710e84 --- /dev/null +++ b/Foundation/include/Poco/PriorityNotificationQueue.h @@ -0,0 +1,180 @@ +// +// PriorityNotificationQueue.h +// +// $Id: //poco/Main/Foundation/include/Poco/PriorityNotificationQueue.h#1 $ +// +// Library: Foundation +// Package: Notifications +// Module: PriorityNotificationQueue +// +// Definition of the PriorityNotificationQueue class. +// +// Copyright (c) 2009, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Foundation_PriorityNotificationQueue_INCLUDED +#define Foundation_PriorityNotificationQueue_INCLUDED + + +#include "Poco/Foundation.h" +#include "Poco/Notification.h" +#include "Poco/Mutex.h" +#include "Poco/Event.h" +#include +#include + + +namespace Poco { + + +class NotificationCenter; + + +class Foundation_API PriorityNotificationQueue + /// A PriorityNotificationQueue object provides a way to implement asynchronous + /// notifications. This is especially useful for sending notifications + /// from one thread to another, for example from a background thread to + /// the main (user interface) thread. + /// + /// The PriorityNotificationQueue is quite similar to the NotificationQueue class. + /// The only difference to NotificationQueue is that each Notification is tagged + /// with a priority value. When inserting a Notification into the queue, the + /// Notification is inserted according to the given priority value, with + /// lower priority values being inserted before higher priority + /// values. Therefore, the lower the numerical priority value, the higher + /// the actual notification priority. + /// + /// Notifications are dequeued in order of their priority. + /// + /// The PriorityNotificationQueue can also be used to distribute work from + /// a controlling thread to one or more worker threads. Each worker thread + /// repeatedly calls waitDequeueNotification() and processes the + /// returned notification. Special care must be taken when shutting + /// down a queue with worker threads waiting for notifications. + /// The recommended sequence to shut down and destroy the queue is to + /// 1. set a termination flag for every worker thread + /// 2. call the wakeUpAll() method + /// 3. join each worker thread + /// 4. destroy the notification queue. +{ +public: + PriorityNotificationQueue(); + /// Creates the PriorityNotificationQueue. + + ~PriorityNotificationQueue(); + /// Destroys the PriorityNotificationQueue. + + void enqueueNotification(Notification::Ptr pNotification, int priority); + /// Enqueues the given notification by adding it to + /// the queue according to the given priority. + /// Lower priority values are inserted before higher priority values. + /// The queue takes ownership of the notification, thus + /// a call like + /// notificationQueue.enqueueNotification(new MyNotification, 1); + /// does not result in a memory leak. + + Notification* dequeueNotification(); + /// Dequeues the next pending notification. + /// Returns 0 (null) if no notification is available. + /// The caller gains ownership of the notification and + /// is expected to release it when done with it. + /// + /// It is highly recommended that the result is immediately + /// assigned to a Notification::Ptr, to avoid potential + /// memory management issues. + + Notification* waitDequeueNotification(); + /// Dequeues the next pending notification. + /// If no notification is available, waits for a notification + /// to be enqueued. + /// The caller gains ownership of the notification and + /// is expected to release it when done with it. + /// This method returns 0 (null) if wakeUpWaitingThreads() + /// has been called by another thread. + /// + /// It is highly recommended that the result is immediately + /// assigned to a Notification::Ptr, to avoid potential + /// memory management issues. + + Notification* waitDequeueNotification(long milliseconds); + /// Dequeues the next pending notification. + /// If no notification is available, waits for a notification + /// to be enqueued up to the specified time. + /// Returns 0 (null) if no notification is available. + /// The caller gains ownership of the notification and + /// is expected to release it when done with it. + /// + /// It is highly recommended that the result is immediately + /// assigned to a Notification::Ptr, to avoid potential + /// memory management issues. + + void dispatch(NotificationCenter& notificationCenter); + /// Dispatches all queued notifications to the given + /// notification center. + + void wakeUpAll(); + /// Wakes up all threads that wait for a notification. + + bool empty() const; + /// Returns true iff the queue is empty. + + int size() const; + /// Returns the number of notifications in the queue. + + void clear(); + /// Removes all notifications from the queue. + + bool hasIdleThreads() const; + /// Returns true if the queue has at least one thread waiting + /// for a notification. + + static PriorityNotificationQueue& defaultQueue(); + /// Returns a reference to the default + /// PriorityNotificationQueue. + +protected: + Notification::Ptr dequeueOne(); + +private: + typedef std::multimap NfQueue; + struct WaitInfo + { + Notification::Ptr pNf; + Event nfAvailable; + }; + typedef std::deque WaitQueue; + + NfQueue _nfQueue; + WaitQueue _waitQueue; + mutable FastMutex _mutex; +}; + + +} // namespace Poco + + +#endif // Foundation_PriorityNotificationQueue_INCLUDED diff --git a/Foundation/include/Poco/TimedNotificationQueue.h b/Foundation/include/Poco/TimedNotificationQueue.h new file mode 100644 index 000000000..85cdb0333 --- /dev/null +++ b/Foundation/include/Poco/TimedNotificationQueue.h @@ -0,0 +1,155 @@ +// +// TimedNotificationQueue.h +// +// $Id: //poco/Main/Foundation/include/Poco/TimedNotificationQueue.h#1 $ +// +// Library: Foundation +// Package: Notifications +// Module: TimedNotificationQueue +// +// Definition of the TimedNotificationQueue class. +// +// Copyright (c) 2009, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef Foundation_TimedNotificationQueue_INCLUDED +#define Foundation_TimedNotificationQueue_INCLUDED + + +#include "Poco/Foundation.h" +#include "Poco/Notification.h" +#include "Poco/Mutex.h" +#include "Poco/Event.h" +#include "Poco/Timestamp.h" +#include + + +namespace Poco { + + +class Foundation_API TimedNotificationQueue + /// A TimedNotificationQueue object provides a way to implement timed, asynchronous + /// notifications. This is especially useful for sending notifications + /// from one thread to another, for example from a background thread to + /// the main (user interface) thread. + /// + /// The TimedNotificationQueue is quite similar to the NotificationQueue class. + /// The only difference to NotificationQueue is that each Notification is tagged + /// with a Timestamp. When inserting a Notification into the queue, the + /// Notification is inserted according to the given Timestamp, with + /// lower Timestamp values being inserted before higher ones. + /// + /// Notifications are dequeued in order of their timestamps. + /// + /// TimedNotificationQueue has some restrictions regarding multithreaded use. + /// While multiple threads may enqueue notifications, only one thread at a + /// time may dequeue notifications from the queue. + /// + /// If two threads try to dequeue a notification simultaneously, the results + /// are undefined. +{ +public: + TimedNotificationQueue(); + /// Creates the TimedNotificationQueue. + + ~TimedNotificationQueue(); + /// Destroys the TimedNotificationQueue. + + void enqueueNotification(Notification::Ptr pNotification, Timestamp timestamp); + /// Enqueues the given notification by adding it to + /// the queue according to the given timestamp. + /// Lower timestamp values are inserted before higher ones. + /// The queue takes ownership of the notification, thus + /// a call like + /// notificationQueue.enqueueNotification(new MyNotification, someTime); + /// does not result in a memory leak. + + Notification* dequeueNotification(); + /// Dequeues the next pending notification with a timestamp + /// less than or equal to the current time. + /// Returns 0 (null) if no notification is available. + /// The caller gains ownership of the notification and + /// is expected to release it when done with it. + /// + /// It is highly recommended that the result is immediately + /// assigned to a Notification::Ptr, to avoid potential + /// memory management issues. + + Notification* waitDequeueNotification(); + /// Dequeues the next pending notification. + /// If no notification is available, waits for a notification + /// to be enqueued. + /// The caller gains ownership of the notification and + /// is expected to release it when done with it. + /// This method returns 0 (null) if wakeUpWaitingThreads() + /// has been called by another thread. + /// + /// It is highly recommended that the result is immediately + /// assigned to a Notification::Ptr, to avoid potential + /// memory management issues. + + Notification* waitDequeueNotification(long milliseconds); + /// Dequeues the next pending notification. + /// If no notification is available, waits for a notification + /// to be enqueued up to the specified time. + /// Returns 0 (null) if no notification is available. + /// The caller gains ownership of the notification and + /// is expected to release it when done with it. + /// + /// It is highly recommended that the result is immediately + /// assigned to a Notification::Ptr, to avoid potential + /// memory management issues. + + bool empty() const; + /// Returns true iff the queue is empty. + + int size() const; + /// Returns the number of notifications in the queue. + + void clear(); + /// Removes all notifications from the queue. + /// + /// Calling clear() while another thread executes one of + /// the dequeue member functions will result in undefined + /// behavior. + +protected: + typedef std::multimap NfQueue; + Notification::Ptr dequeueOne(NfQueue::iterator& it); + bool wait(Timestamp::TimeDiff interval); + +private: + NfQueue _nfQueue; + Event _nfAvailable; + mutable FastMutex _mutex; +}; + + +} // namespace Poco + + +#endif // Foundation_TimedNotificationQueue_INCLUDED diff --git a/Foundation/include/Poco/Timer.h b/Foundation/include/Poco/Timer.h index 02606ea8b..d6500ab32 100644 --- a/Foundation/include/Poco/Timer.h +++ b/Foundation/include/Poco/Timer.h @@ -1,7 +1,7 @@ // // Timer.h // -// $Id: //poco/svn/Foundation/include/Poco/Timer.h#3 $ +// $Id: //poco/Main/Foundation/include/Poco/Timer.h#5 $ // // Library: Foundation // Package: Threading @@ -45,6 +45,7 @@ #include "Poco/Mutex.h" #include "Poco/Event.h" #include "Poco/Thread.h" +#include "Poco/Timestamp.h" namespace Poco { @@ -71,6 +72,14 @@ class Foundation_API Timer: protected Runnable /// factors like operating system, CPU performance and system load and /// may differ from the specified interval. /// + /// The time needed to execute the timer callback is not included + /// in the interval between invocations. For example, if the interval + /// is 500 milliseconds, and the callback needs 400 milliseconds to + /// execute, the callback function is nevertheless called every 500 + /// milliseconds. If the callback takes longer to execute than the + /// interval, the callback function will be immediately called again + /// once it returns. + /// /// The timer thread is taken from a thread pool, so /// there is a limit to the number of available concurrent timers. { @@ -152,6 +161,7 @@ private: Event _wakeUp; Event _done; AbstractTimerCallback* _pCallback; + Poco::Timestamp _nextInvocation; mutable FastMutex _mutex; Timer(const Timer&); diff --git a/Foundation/src/File.cpp b/Foundation/src/File.cpp index 9af07b5d0..70c0b1866 100644 --- a/Foundation/src/File.cpp +++ b/Foundation/src/File.cpp @@ -1,7 +1,7 @@ // // File.cpp // -// $Id: //poco/svn/Foundation/src/File.cpp#3 $ +// $Id: //poco/Main/Foundation/src/File.cpp#22 $ // // Library: Foundation // Package: Filesystem @@ -160,6 +160,12 @@ bool File::isLink() const } +bool File::isDevice() const +{ + return isDeviceImpl(); +} + + bool File::isHidden() const { return isHiddenImpl(); @@ -219,7 +225,7 @@ void File::copyTo(const std::string& path) const Path src(getPathImpl()); Path dest(path); File destFile(path); - if (destFile.exists() && destFile.isDirectory() || dest.isDirectory()) + if ((destFile.exists() && destFile.isDirectory()) || dest.isDirectory()) { dest.makeDirectory(); dest.setFileName(src.getFileName()); diff --git a/Foundation/src/File_UNIX.cpp b/Foundation/src/File_UNIX.cpp index 7ff746446..1379fd9bb 100644 --- a/Foundation/src/File_UNIX.cpp +++ b/Foundation/src/File_UNIX.cpp @@ -1,7 +1,7 @@ // // File_UNIX.cpp // -// $Id: //poco/1.3/Foundation/src/File_UNIX.cpp#12 $ +// $Id: //poco/Main/Foundation/src/File_UNIX.cpp#26 $ // // Library: Foundation // Package: Filesystem @@ -193,6 +193,19 @@ bool FileImpl::isLinkImpl() const } +bool FileImpl::isDeviceImpl() const +{ + poco_assert (!_path.empty()); + + struct stat st; + if (stat(_path.c_str(), &st) == 0) + return S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode); + else + handleLastErrorImpl(_path); + return false; +} + + bool FileImpl::isHiddenImpl() const { poco_assert (!_path.empty()); @@ -443,8 +456,10 @@ void FileImpl::handleLastErrorImpl(const std::string& path) throw FileException("no space left on device", path); case EDQUOT: throw FileException("disk quota exceeded", path); +#if !defined(_AIX) case ENOTEMPTY: throw FileException("directory not empty", path); +#endif case ENAMETOOLONG: throw PathSyntaxException(path); case ENFILE: diff --git a/Foundation/src/File_VMS.cpp b/Foundation/src/File_VMS.cpp index 17992f709..d3c3192f8 100644 --- a/Foundation/src/File_VMS.cpp +++ b/Foundation/src/File_VMS.cpp @@ -1,7 +1,7 @@ // // File_VMS.cpp // -// $Id: //poco/1.3/Foundation/src/File_VMS.cpp#4 $ +// $Id: //poco/Main/Foundation/src/File_VMS.cpp#18 $ // // Library: Foundation // Package: Filesystem @@ -174,6 +174,12 @@ bool FileImpl::isLinkImpl() const } +bool FileImpl::isLinkImpl() const +{ + return false; +} + + bool FileImpl::isHiddenImpl() const { return false; diff --git a/Foundation/src/File_WIN32.cpp b/Foundation/src/File_WIN32.cpp index a31a7c08d..402cf539f 100644 --- a/Foundation/src/File_WIN32.cpp +++ b/Foundation/src/File_WIN32.cpp @@ -1,7 +1,7 @@ // // File_WIN32.cpp // -// $Id: //poco/1.3/Foundation/src/File_WIN32.cpp#8 $ +// $Id: //poco/Main/Foundation/src/File_WIN32.cpp#24 $ // // Library: Foundation // Package: Filesystem @@ -165,12 +165,7 @@ bool FileImpl::canExecuteImpl() const bool FileImpl::isFileImpl() const { - poco_assert (!_path.empty()); - - DWORD attr = GetFileAttributes(_path.c_str()); - if (attr == 0xFFFFFFFF) - handleLastErrorImpl(_path); - return (attr & FILE_ATTRIBUTE_DIRECTORY) == 0; + return !isDirectoryImpl() && !isDeviceImpl(); } @@ -191,6 +186,20 @@ bool FileImpl::isLinkImpl() const } +bool FileImpl::isDeviceImpl() const +{ + poco_assert (!_path.empty()); + + FileHandle fh(_path, GENERIC_READ, 0, OPEN_EXISTING); + DWORD type = GetFileType(fh.get()); + if (type == FILE_TYPE_CHAR) + return true; + else if (type == FILE_TYPE_UNKNOWN && GetLastError() != NO_ERROR) + handleLastErrorImpl(_path); + return false; +} + + bool FileImpl::isHiddenImpl() const { poco_assert (!_path.empty()); @@ -234,7 +243,7 @@ void FileImpl::setLastModifiedImpl(const Timestamp& ts) FILETIME ft; ft.dwLowDateTime = low; ft.dwHighDateTime = high; - FileHandle fh(_path, FILE_ALL_ACCESS, FILE_SHARE_WRITE, OPEN_EXISTING); + FileHandle fh(_path, FILE_ALL_ACCESS, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING); if (SetFileTime(fh.get(), 0, &ft, &ft) == 0) handleLastErrorImpl(_path); } @@ -258,7 +267,7 @@ void FileImpl::setSizeImpl(FileSizeImpl size) { poco_assert (!_path.empty()); - FileHandle fh(_path, GENERIC_WRITE, FILE_SHARE_WRITE, OPEN_EXISTING); + FileHandle fh(_path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING); LARGE_INTEGER li; li.QuadPart = size; if (SetFilePointer(fh.get(), li.LowPart, &li.HighPart, FILE_BEGIN) == -1) diff --git a/Foundation/src/File_WIN32U.cpp b/Foundation/src/File_WIN32U.cpp index 74021e24b..c64a4328e 100644 --- a/Foundation/src/File_WIN32U.cpp +++ b/Foundation/src/File_WIN32U.cpp @@ -1,7 +1,7 @@ // // File_WIN32U.cpp // -// $Id: //poco/1.3/Foundation/src/File_WIN32U.cpp#8 $ +// $Id: //poco/Main/Foundation/src/File_WIN32U.cpp#17 $ // // Library: Foundation // Package: Filesystem @@ -169,12 +169,7 @@ bool FileImpl::canExecuteImpl() const bool FileImpl::isFileImpl() const { - poco_assert (!_path.empty()); - - DWORD attr = GetFileAttributesW(_upath.c_str()); - if (attr == 0xFFFFFFFF) - handleLastErrorImpl(_path); - return (attr & FILE_ATTRIBUTE_DIRECTORY) == 0; + return !isDirectoryImpl() && !isDeviceImpl(); } @@ -195,6 +190,20 @@ bool FileImpl::isLinkImpl() const } +bool FileImpl::isDeviceImpl() const +{ + poco_assert (!_path.empty()); + + FileHandle fh(_path, _upath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING); + DWORD type = GetFileType(fh.get()); + if (type == FILE_TYPE_CHAR) + return true; + else if (type == FILE_TYPE_UNKNOWN && GetLastError() != NO_ERROR) + handleLastErrorImpl(_path); + return false; +} + + bool FileImpl::isHiddenImpl() const { poco_assert (!_path.empty()); @@ -238,7 +247,7 @@ void FileImpl::setLastModifiedImpl(const Timestamp& ts) FILETIME ft; ft.dwLowDateTime = low; ft.dwHighDateTime = high; - FileHandle fh(_path, _upath, FILE_ALL_ACCESS, FILE_SHARE_WRITE, OPEN_EXISTING); + FileHandle fh(_path, _upath, FILE_ALL_ACCESS, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING); if (SetFileTime(fh.get(), 0, &ft, &ft) == 0) handleLastErrorImpl(_path); } @@ -262,7 +271,7 @@ void FileImpl::setSizeImpl(FileSizeImpl size) { poco_assert (!_path.empty()); - FileHandle fh(_path, _upath, GENERIC_WRITE, FILE_SHARE_WRITE, OPEN_EXISTING); + FileHandle fh(_path, _upath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING); LARGE_INTEGER li; li.QuadPart = size; if (SetFilePointer(fh.get(), li.LowPart, &li.HighPart, FILE_BEGIN) == -1) diff --git a/Foundation/src/NotificationCenter.cpp b/Foundation/src/NotificationCenter.cpp index 41f41aa15..6f510fcb8 100644 --- a/Foundation/src/NotificationCenter.cpp +++ b/Foundation/src/NotificationCenter.cpp @@ -1,7 +1,7 @@ // // NotificationCenter.cpp // -// $Id: //poco/svn/Foundation/src/NotificationCenter.cpp#2 $ +// $Id: //poco/Main/Foundation/src/NotificationCenter.cpp#13 $ // // Library: Foundation // Package: Notifications @@ -80,12 +80,11 @@ void NotificationCenter::removeObserver(const AbstractObserver& observer) } -void NotificationCenter::postNotification(Notification* pNotification) +void NotificationCenter::postNotification(Notification::Ptr pNotification) { poco_check_ptr (pNotification); Mutex::ScopedLock lock(_mutex); - AutoPtr pNf = pNotification; ObserverList::iterator it = _observers.begin(); while (it != _observers.end()) { diff --git a/Foundation/src/NotificationQueue.cpp b/Foundation/src/NotificationQueue.cpp index 615a1eeb4..1ab5f84fd 100644 --- a/Foundation/src/NotificationQueue.cpp +++ b/Foundation/src/NotificationQueue.cpp @@ -1,7 +1,7 @@ // // NotificationQueue.cpp // -// $Id: //poco/svn/Foundation/src/NotificationQueue.cpp#2 $ +// $Id: //poco/Main/Foundation/src/NotificationQueue.cpp#15 $ // // Library: Foundation // Package: Notifications @@ -54,7 +54,7 @@ NotificationQueue::~NotificationQueue() } -void NotificationQueue::enqueueNotification(Notification* pNotification) +void NotificationQueue::enqueueNotification(Notification::Ptr pNotification) { poco_check_ptr (pNotification); FastMutex::ScopedLock lock(_mutex); @@ -72,7 +72,7 @@ void NotificationQueue::enqueueNotification(Notification* pNotification) } -void NotificationQueue::enqueueUrgentNotification(Notification* pNotification) +void NotificationQueue::enqueueUrgentNotification(Notification::Ptr pNotification) { poco_check_ptr (pNotification); FastMutex::ScopedLock lock(_mutex); @@ -93,39 +93,37 @@ void NotificationQueue::enqueueUrgentNotification(Notification* pNotification) Notification* NotificationQueue::dequeueNotification() { FastMutex::ScopedLock lock(_mutex); - return dequeueOne(); + return dequeueOne().duplicate(); } Notification* NotificationQueue::waitDequeueNotification() { - Notification* pNf = 0; - WaitInfo* pWI = 0; + Notification::Ptr pNf; + WaitInfo* pWI = 0; { FastMutex::ScopedLock lock(_mutex); pNf = dequeueOne(); - if (pNf) return pNf; + if (pNf) return pNf.duplicate(); pWI = new WaitInfo; - pWI->pNf = 0; _waitQueue.push_back(pWI); } pWI->nfAvailable.wait(); pNf = pWI->pNf; delete pWI; - return pNf; + return pNf.duplicate(); } Notification* NotificationQueue::waitDequeueNotification(long milliseconds) { - Notification* pNf = 0; - WaitInfo* pWI = 0; + Notification::Ptr pNf; + WaitInfo* pWI = 0; { FastMutex::ScopedLock lock(_mutex); pNf = dequeueOne(); - if (pNf) return pNf; + if (pNf) return pNf.duplicate(); pWI = new WaitInfo; - pWI->pNf = 0; _waitQueue.push_back(pWI); } if (pWI->nfAvailable.tryWait(milliseconds)) @@ -146,14 +144,14 @@ Notification* NotificationQueue::waitDequeueNotification(long milliseconds) } } delete pWI; - return pNf; + return pNf.duplicate(); } void NotificationQueue::dispatch(NotificationCenter& notificationCenter) { FastMutex::ScopedLock lock(_mutex); - Notification* pNf = dequeueOne(); + Notification::Ptr pNf = dequeueOne(); while (pNf) { notificationCenter.postNotification(pNf); @@ -183,17 +181,13 @@ bool NotificationQueue::empty() const int NotificationQueue::size() const { FastMutex::ScopedLock lock(_mutex); - return int(_nfQueue.size()); + return static_cast(_nfQueue.size()); } void NotificationQueue::clear() { FastMutex::ScopedLock lock(_mutex); - for (NfQueue::iterator it = _nfQueue.begin(); it != _nfQueue.end(); ++it) - { - (*it)->release(); - } _nfQueue.clear(); } @@ -205,9 +199,9 @@ bool NotificationQueue::hasIdleThreads() const } -Notification* NotificationQueue::dequeueOne() +Notification::Ptr NotificationQueue::dequeueOne() { - Notification* pNf = 0; + Notification::Ptr pNf; if (!_nfQueue.empty()) { pNf = _nfQueue.front(); diff --git a/Foundation/src/PriorityNotificationQueue.cpp b/Foundation/src/PriorityNotificationQueue.cpp new file mode 100644 index 000000000..1ae2f8668 --- /dev/null +++ b/Foundation/src/PriorityNotificationQueue.cpp @@ -0,0 +1,205 @@ +// +// PriorityNotificationQueue.cpp +// +// $Id: //poco/Main/Foundation/src/PriorityNotificationQueue.cpp#1 $ +// +// Library: Foundation +// Package: Notifications +// Module: PriorityNotificationQueue +// +// Copyright (c) 2009, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "Poco/PriorityNotificationQueue.h" +#include "Poco/NotificationCenter.h" +#include "Poco/Notification.h" +#include "Poco/SingletonHolder.h" + + +namespace Poco { + + +PriorityNotificationQueue::PriorityNotificationQueue() +{ +} + + +PriorityNotificationQueue::~PriorityNotificationQueue() +{ + clear(); +} + + +void PriorityNotificationQueue::enqueueNotification(Notification::Ptr pNotification, int priority) +{ + poco_check_ptr (pNotification); + FastMutex::ScopedLock lock(_mutex); + if (_waitQueue.empty()) + { + _nfQueue.insert(NfQueue::value_type(priority, pNotification)); + } + else + { + poco_assert_dbg(_nfQueue.empty()); + WaitInfo* pWI = _waitQueue.front(); + _waitQueue.pop_front(); + pWI->pNf = pNotification; + pWI->nfAvailable.set(); + } +} + + +Notification* PriorityNotificationQueue::dequeueNotification() +{ + FastMutex::ScopedLock lock(_mutex); + return dequeueOne().duplicate(); +} + + +Notification* PriorityNotificationQueue::waitDequeueNotification() +{ + Notification::Ptr pNf; + WaitInfo* pWI = 0; + { + FastMutex::ScopedLock lock(_mutex); + pNf = dequeueOne(); + if (pNf) return pNf.duplicate(); + pWI = new WaitInfo; + _waitQueue.push_back(pWI); + } + pWI->nfAvailable.wait(); + pNf = pWI->pNf; + delete pWI; + return pNf.duplicate(); +} + + +Notification* PriorityNotificationQueue::waitDequeueNotification(long milliseconds) +{ + Notification::Ptr pNf; + WaitInfo* pWI = 0; + { + FastMutex::ScopedLock lock(_mutex); + pNf = dequeueOne(); + if (pNf) return pNf.duplicate(); + pWI = new WaitInfo; + _waitQueue.push_back(pWI); + } + if (pWI->nfAvailable.tryWait(milliseconds)) + { + pNf = pWI->pNf; + } + else + { + FastMutex::ScopedLock lock(_mutex); + pNf = pWI->pNf; + for (WaitQueue::iterator it = _waitQueue.begin(); it != _waitQueue.end(); ++it) + { + if (*it == pWI) + { + _waitQueue.erase(it); + break; + } + } + } + delete pWI; + return pNf.duplicate(); +} + + +void PriorityNotificationQueue::dispatch(NotificationCenter& notificationCenter) +{ + FastMutex::ScopedLock lock(_mutex); + Notification::Ptr pNf = dequeueOne(); + while (pNf) + { + notificationCenter.postNotification(pNf); + pNf = dequeueOne(); + } +} + + +void PriorityNotificationQueue::wakeUpAll() +{ + FastMutex::ScopedLock lock(_mutex); + for (WaitQueue::iterator it = _waitQueue.begin(); it != _waitQueue.end(); ++it) + { + (*it)->nfAvailable.set(); + } + _waitQueue.clear(); +} + + +bool PriorityNotificationQueue::empty() const +{ + FastMutex::ScopedLock lock(_mutex); + return _nfQueue.empty(); +} + + +int PriorityNotificationQueue::size() const +{ + FastMutex::ScopedLock lock(_mutex); + return static_cast(_nfQueue.size()); +} + + +void PriorityNotificationQueue::clear() +{ + FastMutex::ScopedLock lock(_mutex); + _nfQueue.clear(); +} + + +bool PriorityNotificationQueue::hasIdleThreads() const +{ + FastMutex::ScopedLock lock(_mutex); + return !_waitQueue.empty(); +} + + +Notification::Ptr PriorityNotificationQueue::dequeueOne() +{ + Notification::Ptr pNf; + NfQueue::iterator it = _nfQueue.begin(); + if (it != _nfQueue.end()) + { + pNf = it->second; + _nfQueue.erase(it); + } + return pNf; +} + + +PriorityNotificationQueue& PriorityNotificationQueue::defaultQueue() +{ + static SingletonHolder sh; + return *sh.get(); +} + + +} // namespace Poco diff --git a/Foundation/src/TimedNotificationQueue.cpp b/Foundation/src/TimedNotificationQueue.cpp new file mode 100644 index 000000000..ed7ff43f9 --- /dev/null +++ b/Foundation/src/TimedNotificationQueue.cpp @@ -0,0 +1,203 @@ +// +// TimedNotificationQueue.cpp +// +// $Id: //poco/Main/Foundation/src/TimedNotificationQueue.cpp#1 $ +// +// Library: Foundation +// Package: Notifications +// Module: TimedNotificationQueue +// +// Copyright (c) 2009, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "Poco/TimedNotificationQueue.h" +#include "Poco/Notification.h" +#include + + +namespace Poco { + + +TimedNotificationQueue::TimedNotificationQueue() +{ +} + + +TimedNotificationQueue::~TimedNotificationQueue() +{ + clear(); +} + + +void TimedNotificationQueue::enqueueNotification(Notification::Ptr pNotification, Timestamp timestamp) +{ + poco_check_ptr (pNotification); + + FastMutex::ScopedLock lock(_mutex); + _nfQueue.insert(NfQueue::value_type(timestamp, pNotification)); + _nfAvailable.set(); +} + + +Notification* TimedNotificationQueue::dequeueNotification() +{ + FastMutex::ScopedLock lock(_mutex); + + NfQueue::iterator it = _nfQueue.begin(); + if (it != _nfQueue.end()) + { + Timestamp::TimeDiff sleep = -it->first.elapsed(); + if (sleep <= 0) + { + Notification::Ptr pNf = it->second; + _nfQueue.erase(it); + return pNf.duplicate(); + } + } + return 0; +} + + +Notification* TimedNotificationQueue::waitDequeueNotification() +{ + for (;;) + { + _mutex.lock(); + NfQueue::iterator it = _nfQueue.begin(); + if (it != _nfQueue.end()) + { + _mutex.unlock(); + Timestamp::TimeDiff sleep = -it->first.elapsed(); + if (sleep <= 0) + { + return dequeueOne(it).duplicate(); + } + else if (!wait(sleep)) + { + return dequeueOne(it).duplicate(); + } + else continue; + } + else + { + _mutex.unlock(); + } + _nfAvailable.wait(); + } +} + + +Notification* TimedNotificationQueue::waitDequeueNotification(long milliseconds) +{ + while (milliseconds >= 0) + { + _mutex.lock(); + NfQueue::iterator it = _nfQueue.begin(); + if (it != _nfQueue.end()) + { + _mutex.unlock(); + Poco::Timestamp now; + Timestamp::TimeDiff sleep = it->first - now; + if (sleep <= 0) + { + return dequeueOne(it).duplicate(); + } + else if (sleep <= 1000*Timestamp::TimeDiff(milliseconds)) + { + if (!wait(sleep)) + { + return dequeueOne(it).duplicate(); + } + else + { + milliseconds -= static_cast((now.elapsed() + 999)/1000); + continue; + } + } + } + else + { + _mutex.unlock(); + } + if (milliseconds > 0) + { + Poco::Timestamp now; + _nfAvailable.tryWait(milliseconds); + milliseconds -= static_cast((now.elapsed() + 999)/1000); + } + else return 0; + } + return 0; +} + + +bool TimedNotificationQueue::wait(Timestamp::TimeDiff interval) +{ + const Timestamp::TimeDiff MAX_SLEEP = 8*60*60*Timestamp::TimeDiff(1000000); // sleep at most 8 hours at a time + while (interval > 0) + { + Timestamp now; + Timestamp::TimeDiff sleep = interval <= MAX_SLEEP ? interval : MAX_SLEEP; + if (_nfAvailable.tryWait(static_cast((interval + 999)/1000))) + return true; + interval -= now.elapsed(); + } + return false; +} + + +bool TimedNotificationQueue::empty() const +{ + FastMutex::ScopedLock lock(_mutex); + return _nfQueue.empty(); +} + + +int TimedNotificationQueue::size() const +{ + FastMutex::ScopedLock lock(_mutex); + return static_cast(_nfQueue.size()); +} + + +void TimedNotificationQueue::clear() +{ + FastMutex::ScopedLock lock(_mutex); + _nfQueue.clear(); +} + + +Notification::Ptr TimedNotificationQueue::dequeueOne(NfQueue::iterator& it) +{ + FastMutex::ScopedLock lock(_mutex); + Notification::Ptr pNf = it->second; + _nfQueue.erase(it); + return pNf; +} + + +} // namespace Poco diff --git a/Foundation/src/Timer.cpp b/Foundation/src/Timer.cpp index 5b661fcc8..bdfa26566 100644 --- a/Foundation/src/Timer.cpp +++ b/Foundation/src/Timer.cpp @@ -1,7 +1,7 @@ // // Timer.cpp // -// $Id: //poco/svn/Foundation/src/Timer.cpp#3 $ +// $Id: //poco/Main/Foundation/src/Timer.cpp#14 $ // // Library: Foundation // Package: Threading @@ -78,9 +78,13 @@ void Timer::start(const AbstractTimerCallback& method, ThreadPool& threadPool) void Timer::start(const AbstractTimerCallback& method, Thread::Priority priority, ThreadPool& threadPool) { + Poco::Timestamp nextInvocation; + nextInvocation += _startInterval*1000; + poco_assert (!_pCallback); FastMutex::ScopedLock lock(_mutex); + _nextInvocation = nextInvocation; _pCallback = method.clone(); _wakeUp.reset(); threadPool.startWithPriority(priority, *this); @@ -157,14 +161,14 @@ void Timer::setPeriodicInterval(long milliseconds) void Timer::run() { - long interval; - { - FastMutex::ScopedLock lock(_mutex); - interval = _startInterval; - } + Poco::Timestamp now; + long interval(0); do { - if (_wakeUp.tryWait(interval)) + now.update(); + long sleep = static_cast((_nextInvocation - now)/1000); + if (sleep < 0) sleep = 0; + if (_wakeUp.tryWait(sleep)) { FastMutex::ScopedLock lock(_mutex); interval = _periodicInterval; @@ -192,6 +196,7 @@ void Timer::run() interval = _periodicInterval; } } + _nextInvocation += interval*1000; } while (interval > 0); _done.set(); diff --git a/Foundation/testsuite/TestSuite_vs71.vcproj b/Foundation/testsuite/TestSuite_vs71.vcproj index ba4b1042b..d6183683e 100644 --- a/Foundation/testsuite/TestSuite_vs71.vcproj +++ b/Foundation/testsuite/TestSuite_vs71.vcproj @@ -553,6 +553,12 @@ + + + + + + + + + Name="Dynamic"> + Name="Header Files"> + RelativePath=".\src\DynamicTestSuite.h"> + RelativePath=".\src\VarTest.h"> + Name="Source Files"> + RelativePath=".\src\DynamicTestSuite.cpp"> + RelativePath=".\src\VarTest.cpp"> diff --git a/Foundation/testsuite/TestSuite_vs80.vcproj b/Foundation/testsuite/TestSuite_vs80.vcproj index e38035df4..fe07d705f 100644 --- a/Foundation/testsuite/TestSuite_vs80.vcproj +++ b/Foundation/testsuite/TestSuite_vs80.vcproj @@ -762,6 +762,14 @@ RelativePath=".\src\NotificationsTestSuite.cpp" > + + + + + + + + + + + + + + + + 50); - assert (_handled.count("thread2") > 50); - assert (_handled.count("thread3") > 10); + assert (_handled.size() == NOTIFICATION_COUNT); + assert (_handled.count("thread1") > 0); + assert (_handled.count("thread2") > 0); + assert (_handled.count("thread3") > 0); } @@ -217,6 +223,7 @@ void NotificationQueueTest::tearDown() void NotificationQueueTest::work() { + Poco::Random rnd; Thread::sleep(50); Notification* pNf = _queue.waitDequeueNotification(); while (pNf) @@ -225,7 +232,7 @@ void NotificationQueueTest::work() _mutex.lock(); _handled.insert(Thread::current()->name()); _mutex.unlock(); - Thread::yield(); + Thread::sleep(rnd.next(5)); pNf = _queue.waitDequeueNotification(); } } diff --git a/Foundation/testsuite/src/NotificationsTestSuite.cpp b/Foundation/testsuite/src/NotificationsTestSuite.cpp index 779f9d6db..e45739a3d 100644 --- a/Foundation/testsuite/src/NotificationsTestSuite.cpp +++ b/Foundation/testsuite/src/NotificationsTestSuite.cpp @@ -1,7 +1,7 @@ // // NotificationsTestSuite.cpp // -// $Id: //poco/svn/Foundation/testsuite/src/NotificationsTestSuite.cpp#2 $ +// $Id: //poco/Main/Foundation/testsuite/src/NotificationsTestSuite.cpp#9 $ // // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. // and Contributors. @@ -33,6 +33,8 @@ #include "NotificationsTestSuite.h" #include "NotificationCenterTest.h" #include "NotificationQueueTest.h" +#include "PriorityNotificationQueueTest.h" +#include "TimedNotificationQueueTest.h" CppUnit::Test* NotificationsTestSuite::suite() @@ -41,6 +43,8 @@ CppUnit::Test* NotificationsTestSuite::suite() pSuite->addTest(NotificationCenterTest::suite()); pSuite->addTest(NotificationQueueTest::suite()); + pSuite->addTest(PriorityNotificationQueueTest::suite()); + pSuite->addTest(TimedNotificationQueueTest::suite()); return pSuite; } diff --git a/Foundation/testsuite/src/PriorityNotificationQueueTest.cpp b/Foundation/testsuite/src/PriorityNotificationQueueTest.cpp new file mode 100644 index 000000000..9d68987e0 --- /dev/null +++ b/Foundation/testsuite/src/PriorityNotificationQueueTest.cpp @@ -0,0 +1,234 @@ +// +// PriorityNotificationQueueTest.cpp +// +// $Id: //poco/Main/Foundation/testsuite/src/PriorityNotificationQueueTest.cpp#1 $ +// +// Copyright (c) 2009, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "PriorityNotificationQueueTest.h" +#include "CppUnit/TestCaller.h" +#include "CppUnit/TestSuite.h" +#include "Poco/PriorityNotificationQueue.h" +#include "Poco/Notification.h" +#include "Poco/Thread.h" +#include "Poco/Runnable.h" +#include "Poco/RunnableAdapter.h" +#include "Poco/Random.h" + + +using Poco::PriorityNotificationQueue; +using Poco::Notification; +using Poco::Thread; +using Poco::RunnableAdapter; + + +namespace +{ + class QTestNotification: public Notification + { + public: + QTestNotification(const std::string& data): _data(data) + { + } + ~QTestNotification() + { + } + const std::string& data() const + { + return _data; + } + + private: + std::string _data; + }; +} + + +PriorityNotificationQueueTest::PriorityNotificationQueueTest(const std::string& name): CppUnit::TestCase(name) +{ +} + + +PriorityNotificationQueueTest::~PriorityNotificationQueueTest() +{ +} + + +void PriorityNotificationQueueTest::testQueueDequeue() +{ + PriorityNotificationQueue queue; + assert (queue.empty()); + assert (queue.size() == 0); + Notification* pNf = queue.dequeueNotification(); + assertNullPtr(pNf); + queue.enqueueNotification(new Notification, 1); + assert (!queue.empty()); + assert (queue.size() == 1); + pNf = queue.dequeueNotification(); + assertNotNullPtr(pNf); + assert (queue.empty()); + assert (queue.size() == 0); + pNf->release(); + + queue.enqueueNotification(new QTestNotification("first"), 1); + queue.enqueueNotification(new QTestNotification("fourth"), 4); + queue.enqueueNotification(new QTestNotification("third"), 3); + queue.enqueueNotification(new QTestNotification("second"), 2); + assert (!queue.empty()); + assert (queue.size() == 4); + QTestNotification* pTNf = dynamic_cast(queue.dequeueNotification()); + assertNotNullPtr(pTNf); + assert (pTNf->data() == "first"); + pTNf->release(); + assert (!queue.empty()); + assert (queue.size() == 3); + pTNf = dynamic_cast(queue.dequeueNotification()); + assertNotNullPtr(pTNf); + assert (pTNf->data() == "second"); + pTNf->release(); + assert (!queue.empty()); + assert (queue.size() == 2); + pTNf = dynamic_cast(queue.dequeueNotification()); + assertNotNullPtr(pTNf); + assert (pTNf->data() == "third"); + pTNf->release(); + assert (!queue.empty()); + assert (queue.size() == 1); + pTNf = dynamic_cast(queue.dequeueNotification()); + assertNotNullPtr(pTNf); + assert (pTNf->data() == "fourth"); + pTNf->release(); + assert (queue.empty()); + assert (queue.size() == 0); + + pNf = queue.dequeueNotification(); + assertNullPtr(pNf); +} + + +void PriorityNotificationQueueTest::testWaitDequeue() +{ + PriorityNotificationQueue queue; + queue.enqueueNotification(new QTestNotification("third"), 3); + queue.enqueueNotification(new QTestNotification("fourth"), 4); + assert (!queue.empty()); + assert (queue.size() == 2); + QTestNotification* pTNf = dynamic_cast(queue.waitDequeueNotification(10)); + assertNotNullPtr(pTNf); + assert (pTNf->data() == "third"); + pTNf->release(); + assert (!queue.empty()); + assert (queue.size() == 1); + pTNf = dynamic_cast(queue.waitDequeueNotification(10)); + assertNotNullPtr(pTNf); + assert (pTNf->data() == "fourth"); + pTNf->release(); + assert (queue.empty()); + assert (queue.size() == 0); + + Notification* pNf = queue.waitDequeueNotification(10); + assertNullPtr(pNf); +} + + +void PriorityNotificationQueueTest::testThreads() +{ + const int NOTIFICATION_COUNT = 5000; + + Thread t1("thread1"); + Thread t2("thread2"); + Thread t3("thread3"); + + RunnableAdapter ra(*this, &PriorityNotificationQueueTest::work); + t1.start(ra); + t2.start(ra); + t3.start(ra); + for (int i = 0; i < NOTIFICATION_COUNT; ++i) + { + _queue.enqueueNotification(new Notification, 1); + } + while (!_queue.empty()) Thread::sleep(50); + Thread::sleep(20); + _queue.wakeUpAll(); + t1.join(); + t2.join(); + t3.join(); + assert (_handled.size() == NOTIFICATION_COUNT); + assert (_handled.count("thread1") > 0); + assert (_handled.count("thread2") > 0); + assert (_handled.count("thread3") > 0); +} + + +void PriorityNotificationQueueTest::testDefaultQueue() +{ + PriorityNotificationQueue& queue = PriorityNotificationQueue::defaultQueue(); + assert (queue.empty()); + assert (queue.size() == 0); +} + + +void PriorityNotificationQueueTest::setUp() +{ + _handled.clear(); +} + + +void PriorityNotificationQueueTest::tearDown() +{ +} + + +void PriorityNotificationQueueTest::work() +{ + Poco::Random rnd; + Thread::sleep(50); + Notification* pNf = _queue.waitDequeueNotification(); + while (pNf) + { + pNf->release(); + _mutex.lock(); + _handled.insert(Thread::current()->name()); + _mutex.unlock(); + Thread::sleep(rnd.next(5)); + pNf = _queue.waitDequeueNotification(); + } +} + + +CppUnit::Test* PriorityNotificationQueueTest::suite() +{ + CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("PriorityNotificationQueueTest"); + + CppUnit_addTest(pSuite, PriorityNotificationQueueTest, testQueueDequeue); + CppUnit_addTest(pSuite, PriorityNotificationQueueTest, testWaitDequeue); + CppUnit_addTest(pSuite, PriorityNotificationQueueTest, testThreads); + CppUnit_addTest(pSuite, PriorityNotificationQueueTest, testDefaultQueue); + + return pSuite; +} diff --git a/Foundation/testsuite/src/PriorityNotificationQueueTest.h b/Foundation/testsuite/src/PriorityNotificationQueueTest.h new file mode 100644 index 000000000..c2a13d75a --- /dev/null +++ b/Foundation/testsuite/src/PriorityNotificationQueueTest.h @@ -0,0 +1,72 @@ +// +// PriorityNotificationQueueTest.h +// +// $Id: //poco/Main/Foundation/testsuite/src/PriorityNotificationQueueTest.h#1 $ +// +// Definition of the PriorityNotificationQueueTest class. +// +// Copyright (c) 2009, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef PriorityNotificationQueueTest_INCLUDED +#define PriorityNotificationQueueTest_INCLUDED + + +#include "Poco/Foundation.h" +#include "CppUnit/TestCase.h" +#include "Poco/PriorityNotificationQueue.h" +#include "Poco/Mutex.h" +#include + + +class PriorityNotificationQueueTest: public CppUnit::TestCase +{ +public: + PriorityNotificationQueueTest(const std::string& name); + ~PriorityNotificationQueueTest(); + + void testQueueDequeue(); + void testWaitDequeue(); + void testThreads(); + void testDefaultQueue(); + + void setUp(); + void tearDown(); + + static CppUnit::Test* suite(); + +protected: + void work(); + +private: + Poco::PriorityNotificationQueue _queue; + std::multiset _handled; + Poco::FastMutex _mutex; +}; + + +#endif // PriorityNotificationQueueTest_INCLUDED diff --git a/Foundation/testsuite/src/TimedNotificationQueueTest.cpp b/Foundation/testsuite/src/TimedNotificationQueueTest.cpp new file mode 100644 index 000000000..73ca0721d --- /dev/null +++ b/Foundation/testsuite/src/TimedNotificationQueueTest.cpp @@ -0,0 +1,291 @@ +// +// TimedNotificationQueueTest.cpp +// +// $Id: //poco/Main/Foundation/testsuite/src/TimedNotificationQueueTest.cpp#1 $ +// +// Copyright (c) 2009, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#include "TimedNotificationQueueTest.h" +#include "CppUnit/TestCaller.h" +#include "CppUnit/TestSuite.h" +#include "Poco/TimedNotificationQueue.h" +#include "Poco/Notification.h" +#include "Poco/Timestamp.h" + + +using Poco::TimedNotificationQueue; +using Poco::Notification; +using Poco::Timestamp; + + +namespace +{ + class QTestNotification: public Notification + { + public: + QTestNotification(const std::string& data): _data(data) + { + } + ~QTestNotification() + { + } + const std::string& data() const + { + return _data; + } + + private: + std::string _data; + }; +} + + +TimedNotificationQueueTest::TimedNotificationQueueTest(const std::string& name): CppUnit::TestCase(name) +{ +} + + +TimedNotificationQueueTest::~TimedNotificationQueueTest() +{ +} + + +void TimedNotificationQueueTest::testDequeue() +{ + TimedNotificationQueue queue; + assert (queue.empty()); + assert (queue.size() == 0); + Notification* pNf = queue.dequeueNotification(); + assertNullPtr(pNf); + queue.enqueueNotification(new Notification, Timestamp()); + assert (!queue.empty()); + assert (queue.size() == 1); + pNf = queue.dequeueNotification(); + assertNotNullPtr(pNf); + assert (queue.empty()); + assert (queue.size() == 0); + pNf->release(); + + Poco::Timestamp ts1; + ts1 += 100000; + Poco::Timestamp ts2; + ts2 += 200000; + Poco::Timestamp ts3; + ts3 += 300000; + Poco::Timestamp ts4; + ts4 += 400000; + + queue.enqueueNotification(new QTestNotification("first"), ts1); + queue.enqueueNotification(new QTestNotification("fourth"), ts4); + queue.enqueueNotification(new QTestNotification("third"), ts3); + queue.enqueueNotification(new QTestNotification("second"), ts2); + assert (!queue.empty()); + assert (queue.size() == 4); + QTestNotification* pTNf = 0; + while (!pTNf) + { + pTNf = dynamic_cast(queue.dequeueNotification()); + } + assertNotNullPtr(pTNf); + assert (pTNf->data() == "first"); + pTNf->release(); + assert (ts1.elapsed() >= 0); + assert (!queue.empty()); + assert (queue.size() == 3); + + pTNf = 0; + while (!pTNf) + { + pTNf = dynamic_cast(queue.dequeueNotification()); + } + assertNotNullPtr(pTNf); + assert (pTNf->data() == "second"); + pTNf->release(); + assert (ts2.elapsed() >= 0); + assert (!queue.empty()); + assert (queue.size() == 2); + + pTNf = 0; + while (!pTNf) + { + pTNf = dynamic_cast(queue.dequeueNotification()); + } + assertNotNullPtr(pTNf); + assert (pTNf->data() == "third"); + pTNf->release(); + assert (ts3.elapsed() >= 0); + assert (!queue.empty()); + assert (queue.size() == 1); + + pTNf = 0; + while (!pTNf) + { + pTNf = dynamic_cast(queue.dequeueNotification()); + } + assertNotNullPtr(pTNf); + assert (pTNf->data() == "fourth"); + pTNf->release(); + assert (ts4.elapsed() >= 0); + assert (queue.empty()); + assert (queue.size() == 0); + + pNf = queue.dequeueNotification(); + assertNullPtr(pNf); +} + + +void TimedNotificationQueueTest::testWaitDequeue() +{ + TimedNotificationQueue queue; + + Poco::Timestamp ts1; + ts1 += 100000; + Poco::Timestamp ts2; + ts2 += 200000; + Poco::Timestamp ts3; + ts3 += 300000; + Poco::Timestamp ts4; + ts4 += 400000; + + queue.enqueueNotification(new QTestNotification("first"), ts1); + queue.enqueueNotification(new QTestNotification("fourth"), ts4); + queue.enqueueNotification(new QTestNotification("third"), ts3); + queue.enqueueNotification(new QTestNotification("second"), ts2); + assert (!queue.empty()); + assert (queue.size() == 4); + QTestNotification* pTNf = dynamic_cast(queue.waitDequeueNotification()); + assertNotNullPtr(pTNf); + assert (pTNf->data() == "first"); + pTNf->release(); + assert (ts1.elapsed() >= 0); + assert (!queue.empty()); + assert (queue.size() == 3); + + pTNf = dynamic_cast(queue.waitDequeueNotification()); + assertNotNullPtr(pTNf); + assert (pTNf->data() == "second"); + pTNf->release(); + assert (ts2.elapsed() >= 0); + assert (!queue.empty()); + assert (queue.size() == 2); + + pTNf = dynamic_cast(queue.waitDequeueNotification()); + assertNotNullPtr(pTNf); + assert (pTNf->data() == "third"); + pTNf->release(); + assert (ts3.elapsed() >= 0); + assert (!queue.empty()); + assert (queue.size() == 1); + + pTNf = dynamic_cast(queue.waitDequeueNotification()); + assertNotNullPtr(pTNf); + assert (pTNf->data() == "fourth"); + pTNf->release(); + assert (ts4.elapsed() >= 0); + assert (queue.empty()); + assert (queue.size() == 0); +} + + +void TimedNotificationQueueTest::testWaitDequeueTimeout() +{ + TimedNotificationQueue queue; + + Poco::Timestamp ts1; + ts1 += 200000; + Poco::Timestamp ts2; + ts2 += 400000; + Poco::Timestamp ts3; + ts3 += 600000; + Poco::Timestamp ts4; + ts4 += 800000; + + queue.enqueueNotification(new QTestNotification("first"), ts1); + queue.enqueueNotification(new QTestNotification("fourth"), ts4); + queue.enqueueNotification(new QTestNotification("third"), ts3); + queue.enqueueNotification(new QTestNotification("second"), ts2); + assert (!queue.empty()); + assert (queue.size() == 4); + QTestNotification* pTNf = dynamic_cast(queue.waitDequeueNotification(10)); + assertNullPtr(pTNf); + pTNf = dynamic_cast(queue.waitDequeueNotification(20)); + assertNullPtr(pTNf); + pTNf = dynamic_cast(queue.waitDequeueNotification(200)); + assertNotNullPtr(pTNf); + assert (pTNf->data() == "first"); + pTNf->release(); + assert (ts1.elapsed() >= 0); + assert (!queue.empty()); + assert (queue.size() == 3); + + pTNf = dynamic_cast(queue.waitDequeueNotification(220)); + assertNotNullPtr(pTNf); + assert (pTNf->data() == "second"); + pTNf->release(); + assert (ts2.elapsed() >= 0); + assert (!queue.empty()); + assert (queue.size() == 2); + + pTNf = dynamic_cast(queue.waitDequeueNotification(220)); + assertNotNullPtr(pTNf); + assert (pTNf->data() == "third"); + pTNf->release(); + assert (ts3.elapsed() >= 0); + assert (!queue.empty()); + assert (queue.size() == 1); + + pTNf = dynamic_cast(queue.waitDequeueNotification(220)); + assertNotNullPtr(pTNf); + assert (pTNf->data() == "fourth"); + pTNf->release(); + assert (ts1.elapsed() >= 0); + assert (queue.empty()); + assert (queue.size() == 0); +} + + +void TimedNotificationQueueTest::setUp() +{ +} + + +void TimedNotificationQueueTest::tearDown() +{ +} + + +CppUnit::Test* TimedNotificationQueueTest::suite() +{ + CppUnit::TestSuite* pSuite = new CppUnit::TestSuite("TimedNotificationQueueTest"); + + CppUnit_addTest(pSuite, TimedNotificationQueueTest, testDequeue); + CppUnit_addTest(pSuite, TimedNotificationQueueTest, testWaitDequeue); + CppUnit_addTest(pSuite, TimedNotificationQueueTest, testWaitDequeueTimeout); + + return pSuite; +} diff --git a/Foundation/testsuite/src/TimedNotificationQueueTest.h b/Foundation/testsuite/src/TimedNotificationQueueTest.h new file mode 100644 index 000000000..4f48d0de9 --- /dev/null +++ b/Foundation/testsuite/src/TimedNotificationQueueTest.h @@ -0,0 +1,68 @@ +// +// TimedNotificationQueueTest.h +// +// $Id: //poco/Main/Foundation/testsuite/src/TimedNotificationQueueTest.h#1 $ +// +// Definition of the TimedNotificationQueueTest class. +// +// Copyright (c) 2009, Applied Informatics Software Engineering GmbH. +// and Contributors. +// +// Permission is hereby granted, free of charge, to any person or organization +// obtaining a copy of the software and accompanying documentation covered by +// this license (the "Software") to use, reproduce, display, distribute, +// execute, and transmit the Software, and to prepare derivative works of the +// Software, and to permit third-parties to whom the Software is furnished to +// do so, all subject to the following: +// +// The copyright notices in the Software and this entire statement, including +// the above license grant, this restriction and the following disclaimer, +// must be included in all copies of the Software, in whole or in part, and +// all derivative works of the Software, unless such copies or derivative +// works are solely in the form of machine-executable object code generated by +// a source language processor. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. +// + + +#ifndef TimedNotificationQueueTest_INCLUDED +#define TimedNotificationQueueTest_INCLUDED + + +#include "Poco/Foundation.h" +#include "CppUnit/TestCase.h" +#include "Poco/TimedNotificationQueue.h" +#include "Poco/Mutex.h" +#include + + +class TimedNotificationQueueTest: public CppUnit::TestCase +{ +public: + TimedNotificationQueueTest(const std::string& name); + ~TimedNotificationQueueTest(); + + void testDequeue(); + void testWaitDequeue(); + void testWaitDequeueTimeout(); + + void setUp(); + void tearDown(); + + static CppUnit::Test* suite(); + +protected: + void work(); + +private: +}; + + +#endif // TimedNotificationQueueTest_INCLUDED