Subversion Repositories public

Rev

Rev 49 | Rev 55 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 49 Rev 51
Line 48... Line 48...
48
/**
48
/**
49
 * It prepends the message by the function name.
49
 * It prepends the message by the function name.
50
 */
50
 */
51
#define IN_EXC_MSG(msg) (std::string(__PRETTY_FUNCTION__) + ": " + msg)
51
#define IN_EXC_MSG(msg) (std::string(__PRETTY_FUNCTION__) + ": " + msg)
52
52
-
 
53
/// inotify-cxx thread safety
-
 
54
/**
-
 
55
 * If this symbol is defined you can use this interface safely
-
 
56
 * threaded applications. Remember that it slightly degrades
-
 
57
 * performance.
-
 
58
 *
-
 
59
 * Even if INOTIFY_THREAD_SAFE is defined some classes stay
-
 
60
 * unsafe. If you must use them (must you?) in more than one
-
 
61
 * thread concurrently you need to implement explicite locking.
-
 
62
 *
-
 
63
 * You need not to define INOTIFY_THREAD_SAFE in that cases
-
 
64
 * where the application is multithreaded but all the inotify
-
 
65
 * infrastructure will be managed only in one thread. This is
-
 
66
 * the recommended way.
-
 
67
 *
-
 
68
 * Locking may fail (it is very rare but not impossible). In this
-
 
69
 * case an exception is thrown. But if unlocking fails in case
-
 
70
 * of an error it does nothing (this failure is ignored).
-
 
71
 */
-
 
72
#ifdef INOTIFY_THREAD_SAFE
-
 
73
-
 
74
#include <pthread.h>
-
 
75
-
 
76
#define IN_LOCK_DECL mutable pthread_rwlock_t __m_lock;
-
 
77
-
 
78
#define IN_LOCK_INIT \
-
 
79
  { \
-
 
80
    pthread_rwlockattr_t attr; \
-
 
81
    int res = 0; \
-
 
82
    if ((res = pthread_rwlockattr_init(&attr)) != 0) \
-
 
83
      throw InotifyException(IN_EXC_MSG("cannot initialize lock attributes"), res, this); \
-
 
84
    if ((res = pthread_rwlockattr_setkind_np(&attr, PTHREAD_RWLOCK_PREFER_WRITER_NP)) != 0) \
-
 
85
      throw InotifyException(IN_EXC_MSG("cannot set lock kind"), res, this); \
-
 
86
    if ((res = pthread_rwlock_init(&__m_lock, &attr)) != 0) \
-
 
87
      throw InotifyException(IN_EXC_MSG("cannot initialize lock"), res, this); \
-
 
88
    pthread_rwlockattr_destroy(&attr); \
-
 
89
  }
-
 
90
 
-
 
91
#define IN_LOCK_DONE pthread_rwlock_destroy(&__m_lock);
-
 
92
-
 
93
#define IN_READ_BEGIN \
-
 
94
  { \
-
 
95
    int res = pthread_rwlock_rdlock(&__m_lock); \
-
 
96
    if (res != 0) \
-
 
97
      throw InotifyException(IN_EXC_MSG("locking for reading failed"), res, (void*) this); \
-
 
98
  }
-
 
99
 
-
 
100
#define IN_READ_END \
-
 
101
  { \
-
 
102
    int res = pthread_rwlock_unlock(&__m_lock); \
-
 
103
    if (res != 0) \
-
 
104
      throw InotifyException(IN_EXC_MSG("unlocking failed"), res, (void*) this); \
-
 
105
  }
-
 
106
 
-
 
107
#define IN_READ_END_NOTHROW pthread_rwlock_unlock(&__m_lock);
-
 
108
 
-
 
109
#define IN_WRITE_BEGIN \
-
 
110
  { \
-
 
111
    int res = pthread_rwlock_wrlock(&__m_lock); \
-
 
112
    if (res != 0) \
-
 
113
      throw InotifyException(IN_EXC_MSG("locking for writing failed"), res, (void*) this); \
-
 
114
  }
-
 
115
 
-
 
116
#define IN_WRITE_END IN_READ_END
-
 
117
#define IN_WRITE_END_NOTHROW IN_READ_END_NOTHROW
-
 
118
-
 
119
#else // INOTIFY_THREAD_SAFE
-
 
120
-
 
121
#define IN_LOCK_DECL
-
 
122
#define IN_LOCK_INIT
-
 
123
#define IN_LOCK_DONE
-
 
124
#define IN_READ_BEGIN
-
 
125
#define IN_READ_END
-
 
126
#define IN_READ_END_NOTHROW
-
 
127
#define IN_WRITE_BEGIN
-
 
128
#define IN_WRITE_END
-
 
129
#define IN_WRITE_END_NOTHROW
-
 
130
-
 
131
#endif // INOTIFY_THREAD_SAFE
-
 
132
-
 
133
53
134
54
135
55
// forward declaration
136
// forward declaration
56
class InotifyWatch;
137
class InotifyWatch;
57
class Inotify;
138
class Inotify;
58
139
59
140
60
/// Class for inotify exceptions
141
/// Class for inotify exceptions
-
 
142
/**
-
 
143
 * This class allows to acquire information about exceptional
-
 
144
 * events. It makes easier to log or display error messages
-
 
145
 * and to identify problematic code locations.
-
 
146
 *
-
 
147
 * Although this class is basically thread-safe it is not intended
-
 
148
 * to be shared between threads.
-
 
149
 */
61
class InotifyException
150
class InotifyException
62
{
151
{
63
public:
152
public:
64
  /// Constructor
153
  /// Constructor
65
  /**
154
  /**
Line 112... Line 201...
112
201
113
/// inotify event class
202
/// inotify event class
114
/**
203
/**
115
 * It holds all information about inotify event and provides
204
 * It holds all information about inotify event and provides
116
 * access to its particular values.
205
 * access to its particular values.
-
 
206
 *
-
 
207
 * This class is not (and is not intended to be) thread-safe
-
 
208
 * and therefore it must not be used concurrently in multiple
-
 
209
 * threads.
117
 */
210
 */
118
class InotifyEvent
211
class InotifyEvent
119
{
212
{
120
public:
213
public:
121
  /// Constructor.
214
  /// Constructor.
Line 269... Line 362...
269
};
362
};
270
363
271
364
272
365
273
/// inotify watch class
366
/// inotify watch class
-
 
367
/**
-
 
368
 * It holds information about the inotify watch on a particular
-
 
369
 * inode.
-
 
370
 *
-
 
371
 * If the INOTIFY_THREAD_SAFE is defined this class is thread-safe.
-
 
372
 */
274
class InotifyWatch
373
class InotifyWatch
275
{
374
{
276
public:
375
public:
277
  /// Constructor.
376
  /// Constructor.
278
  /**
377
  /**
Line 287... Line 386...
287
  : m_path(rPath),
386
  : m_path(rPath),
288
    m_uMask(uMask),
387
    m_uMask(uMask),
289
    m_wd((int32_t) -1),
388
    m_wd((int32_t) -1),
290
    m_fEnabled(fEnabled)
389
    m_fEnabled(fEnabled)
291
  {
390
  {
292
   
-
 
-
 
391
    IN_LOCK_INIT
293
  }
392
  }
294
 
393
 
295
  /// Destructor.
394
  /// Destructor.
296
  ~InotifyWatch() {}
395
  ~InotifyWatch()
-
 
396
  {
-
 
397
    IN_LOCK_DONE
-
 
398
  }
297
 
399
 
298
  /// Returns the watch descriptor.
400
  /// Returns the watch descriptor.
299
  /**
401
  /**
300
   * \return watch descriptor; -1 for inactive watch
402
   * \return watch descriptor; -1 for inactive watch
301
   */
403
   */
Line 322... Line 424...
322
    return (uint32_t) m_uMask;
424
    return (uint32_t) m_uMask;
323
  }
425
  }
324
 
426
 
325
  /// Sets the watch event mask.
427
  /// Sets the watch event mask.
326
  /**
428
  /**
327
   * If the watch is active (added to an instance of Inofify)
429
   * If the watch is active (added to an instance of Inotify)
328
   * this method may fail due to unsuccessful re-setting
430
   * this method may fail due to unsuccessful re-setting
329
   * the watch in the kernel.
431
   * the watch in the kernel.
330
   *
432
   *
331
   * \param[in] uMask event mask
433
   * \param[in] uMask event mask
332
   *
434
   *
Line 343... Line 445...
343
    return m_pInotify;
445
    return m_pInotify;
344
  }
446
  }
345
 
447
 
346
  /// Enables/disables the watch.
448
  /// Enables/disables the watch.
347
  /**
449
  /**
348
   * If the watch is active (added to an instance of Inofify)
450
   * If the watch is active (added to an instance of Inotify)
349
   * this method may fail due to unsuccessful re-setting
451
   * this method may fail due to unsuccessful re-setting
350
   * the watch in the kernel.
452
   * the watch in the kernel.
351
   *
453
   *
352
   * Re-setting the current state has no effect.
454
   * Re-setting the current state has no effect.
353
   *
455
   *
Line 372... Line 474...
372
  std::string m_path;   ///< watched file path
474
  std::string m_path;   ///< watched file path
373
  uint32_t m_uMask;     ///< event mask
475
  uint32_t m_uMask;     ///< event mask
374
  int32_t m_wd;         ///< watch descriptor
476
  int32_t m_wd;         ///< watch descriptor
375
  Inotify* m_pInotify;  ///< inotify object
477
  Inotify* m_pInotify;  ///< inotify object
376
  bool m_fEnabled;      ///< events enabled yes/no
478
  bool m_fEnabled;      ///< events enabled yes/no
-
 
479
 
-
 
480
  IN_LOCK_DECL
377
};
481
};
378
482
379
483
380
/// Mapping from watch descriptors to watch objects.
484
/// Mapping from watch descriptors to watch objects.
381
typedef std::map<int32_t, InotifyWatch*> IN_WATCH_MAP;
485
typedef std::map<int32_t, InotifyWatch*> IN_WATCH_MAP;
Line 383... Line 487...
383
/// Mapping from paths to watch objects.
487
/// Mapping from paths to watch objects.
384
typedef std::map<std::string, InotifyWatch*> IN_WP_MAP;
488
typedef std::map<std::string, InotifyWatch*> IN_WP_MAP;
385
489
386
490
387
/// inotify class
491
/// inotify class
-
 
492
/**
-
 
493
 * It holds information about the inotify device descriptor
-
 
494
 * and manages the event queue.
-
 
495
 *
-
 
496
 * If the INOTIFY_THREAD_SAFE is defined this class is thread-safe.
-
 
497
 */
388
class Inotify
498
class Inotify
389
{
499
{
390
public:
500
public:
391
  /// Constructor.
501
  /// Constructor.
392
  /**
502
  /**
Line 455... Line 565...
455
  /**
565
  /**
456
   * This is the total count of all watches (regardless whether
566
   * This is the total count of all watches (regardless whether
457
   * enabled or not).
567
   * enabled or not).
458
   *
568
   *
459
   * \return count of watches
569
   * \return count of watches
-
 
570
   *
-
 
571
   * \sa GetEnabledCount()
460
   */
572
   */
461
  inline size_t GetWatchCount() const
573
  inline size_t GetWatchCount() const
462
  {
574
  {
-
 
575
    IN_READ_BEGIN
463
    return (size_t) m_paths.size();
576
    size_t n = (size_t) m_paths.size();
-
 
577
    IN_READ_END
-
 
578
    return n;
-
 
579
  }
-
 
580
 
-
 
581
  /// Returns the count of enabled watches.
-
 
582
  /**
-
 
583
   * \return count of enabled watches
-
 
584
   *
-
 
585
   * \sa GetWatchCount()
-
 
586
   */  
-
 
587
  inline size_t GetEnabledCount() const
-
 
588
  {
-
 
589
    IN_READ_BEGIN
-
 
590
    size_t n = (size_t) m_watches.size();
-
 
591
    IN_READ_END
-
 
592
    return n;
464
  }
593
  }
465
 
594
 
466
  /// Waits for inotify events.
595
  /// Waits for inotify events.
467
  /**
596
  /**
468
   * It waits until one or more events occur. When called
597
   * It waits until one or more events occur. When called
Line 482... Line 611...
482
   * This number is related to the events in the queue inside
611
   * This number is related to the events in the queue inside
483
   * this object, not to the events pending in the kernel.
612
   * this object, not to the events pending in the kernel.
484
   *
613
   *
485
   * \return count of events
614
   * \return count of events
486
   */
615
   */
487
  int GetEventCount();
616
  inline size_t GetEventCount()
-
 
617
  {
-
 
618
    IN_READ_BEGIN
-
 
619
    size_t n = (size_t) m_events.size();
-
 
620
    IN_READ_END
-
 
621
    return n;
-
 
622
  }
488
 
623
 
489
  /// Extracts a queued inotify event.
624
  /// Extracts a queued inotify event.
490
  /**
625
  /**
491
   * The extracted event is removed from the queue.
626
   * The extracted event is removed from the queue.
492
   * If the pointer is NULL it does nothing.
627
   * If the pointer is NULL it does nothing.
Line 589... Line 724...
589
  IN_WATCH_MAP m_watches;               ///< watches (by descriptors)
724
  IN_WATCH_MAP m_watches;               ///< watches (by descriptors)
590
  IN_WP_MAP m_paths;                    ///< watches (by paths)
725
  IN_WP_MAP m_paths;                    ///< watches (by paths)
591
  unsigned char m_buf[INOTIFY_BUFLEN];  ///< buffer for events
726
  unsigned char m_buf[INOTIFY_BUFLEN];  ///< buffer for events
592
  std::deque<InotifyEvent> m_events;    ///< event queue
727
  std::deque<InotifyEvent> m_events;    ///< event queue
593
 
728
 
-
 
729
  IN_LOCK_DECL
-
 
730
 
594
  friend class InotifyWatch;
731
  friend class InotifyWatch;
595
};
732
};
596
733
597
734
598
#endif //_INOTIFYCXX_H_
735
#endif //_INOTIFYCXX_H_
-
 
736