summaryrefslogtreecommitdiff
path: root/ace/Log_Msg.h
blob: de764e69d71fdb8a6ef1ee47c0e3b340b6cf6a4b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
// -*- C++ -*-

//=============================================================================
/**
 *  @file    Log_Msg.h
 *
 *  $Id$
 *
 *  @author Douglas C. Schmidt <schmidt@cs.wustl.edu>
 */
//=============================================================================

#ifndef ACE_LOG_MSG_H
#define ACE_LOG_MSG_H
#include "ace/pre.h"

// This stuff must come first to avoid problems with circular
// headers...
// ... but ACE_NDEBUG and ACE_NLOGGING can come from the config.h file, so
// pull that one early.
#include "ace/config-all.h"

// The following ASSERT macro is courtesy of Alexandre Karev
// <akg@na47sun05.cern.ch>.
#if defined (ACE_NDEBUG)
#define ACE_ASSERT(x)
#elif !defined (ACE_ASSERT)
#define ACE_ASSERT(X) \
  do { if(!(X)) { \
  int __ace_error = ACE_OS::last_error (); \
  ACE_Log_Msg *ace___ = ACE_Log_Msg::instance (); \
  ace___->set (__FILE__, __LINE__, -1, __ace_error, ace___->restart (), \
               ace___->msg_ostream (), ace___->msg_callback ()); \
  ace___->log (LM_ERROR, ACE_LIB_TEXT ("ACE_ASSERT: file %N, line %l assertion failed for '%s'.%a\n"), #X, -1); \
  } } while (0)
#endif  /* ACE_NDEBUG */

#if defined (ACE_NLOGGING)
#define ACE_HEX_DUMP(X) do {} while (0)
#define ACE_RETURN(Y) do { return (Y); } while (0)
#define ACE_ERROR_RETURN(X, Y) return (Y)
#define ACE_ERROR_BREAK(X) { break; }
#define ACE_ERROR(X) do {} while (0)
#define ACE_DEBUG(X) do {} while (0)
#define ACE_ERROR_INIT(VALUE, FLAGS)
#else
#define ACE_HEX_DUMP(X) \
  do { \
    int __ace_error = ACE_OS::last_error (); \
    ACE_Log_Msg *ace___ = ACE_Log_Msg::instance (); \
    ace___->conditional_set (__FILE__, __LINE__, 0, __ace_error); \
    ace___->log_hexdump X; \
  } while (0)
#define ACE_RETURN(Y) \
  do { \
    int __ace_error = ACE_OS::last_error (); \
    ACE_Log_Msg *ace___ = ACE_Log_Msg::instance (); \
    ace___->set (__FILE__, __LINE__, Y, __ace_error, ace___->restart (), \
                 ace___->msg_ostream (), ace___->msg_callback ()); \
    return Y; \
  } while (0)
#define ACE_ERROR_RETURN(X, Y) \
  do { \
    int __ace_error = ACE_OS::last_error (); \
    ACE_Log_Msg *ace___ = ACE_Log_Msg::instance (); \
    ace___->conditional_set (__FILE__, __LINE__, Y, __ace_error); \
    ace___->log X; \
    return Y; \
  } while (0)
#define ACE_ERROR(X) \
  do { \
    int __ace_error = ACE_OS::last_error (); \
    ACE_Log_Msg *ace___ = ACE_Log_Msg::instance (); \
    ace___->conditional_set (__FILE__, __LINE__, -1, __ace_error); \
    ace___->log X; \
  } while (0)
#define ACE_DEBUG(X) \
  do { \
    int __ace_error = ACE_OS::last_error (); \
    ACE_Log_Msg *ace___ = ACE_Log_Msg::instance (); \
    ace___->conditional_set (__FILE__, __LINE__, 0, __ace_error); \
    ace___->log X; \
  } while (0)
#define ACE_ERROR_INIT(VALUE, FLAGS) \
  do { \
    ACE_Log_Msg *ace___ = ACE_Log_Msg::instance (); \
    ace___->set_flags (FLAGS); ace___->op_status (VALUE); \
  } while (0)
#define ACE_ERROR_BREAK(X) { ACE_ERROR (X); break; }
#endif /* ACE_NLOGGING */

#include "ace/Log_Record.h"
#include "ace/OS_Log_Msg_Attributes.h"

#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */

#if defined (__Lynx__)
# undef STDERR
#endif /* __Lynx__ */

#if defined (THREAD)
// This workaround is necessary for nasty libraries that #define
// THREAD 1.
#define ACE_THREAD_HACK THREAD
#undef THREAD
#endif /* THREAD */

class ACE_Log_Msg_Callback;

// ****************************************************************

#define ACE_LOG_MSG ACE_Log_Msg::instance ()

// Forward declaration
class ACE_Thread_Descriptor;

/**
 * @class ACE_Log_Msg
 *
 * @brief Provides a variable length argument message logging
 * abstraction.
 *
 * This class is very flexible since it allows formatted error
 * messages to be printed in a thread-safe manner to various
 * locations, such as stdout, stderr, cerr, a distributed logger, etc.
 * The current message is also kept in a thread-specific storage
 * location (i.e., there is one ACE_Log_Msg object per-thread), which
 * can be used to communicate errors between framework methods and
 * callers.  A message is logged by the log() method, only if the
 * message priority is currently enabled.  Moreover, only the current
 * log message is stored here -- it will be overwritten by the
 * subsequent call to <log>.
 *
 * The ACE_Log_Msg class uses two priority masks to control its
 * logging behavior.  The <priority_mask_> object attribute is thread
 * specific and specifies the priority levels logged by the thread.
 * The <process_priority_mask_> class attribute is not thread-specific
 * and specifies the priority levels that will be logged by all
 * threads in the process.  By default, all levels are enabled for
 * <priority_mask_> and all levels are disabled for
 * <process_priority_mask_> (i.e. each thread determines which
 * priority levels will be logged).  Both priority masks can be
 * modified using the priority_mask() method of this class.
 */
class ACE_Export ACE_Log_Msg
{

public:
  // Logger Flags.
  enum
  {
    /// Write messages to stderr.
    STDERR = 1,
    /// Write messages to the local client logger deamon.
    LOGGER = 2,
    /// Write messages to the ostream * stored in thread-specific
    /// storage.
    OSTREAM = 4,
    /// Write messages to the callback object.
    MSG_CALLBACK = 8,
    /// Display messages in a verbose manner.
    VERBOSE = 16,
    /// Display messages in a less verbose manner (i.e., only print
    /// information that can change between calls).
    VERBOSE_LITE = 32,
    /// Do not print messages at all (just leave in thread-specific
    /// storage for later inspection).
    SILENT = 64,
    /// Write messages to the system's event log.
    SYSLOG = 128
 };

  // = Initialization and termination routines.

  /// Returns a pointer to the Singleton.
  static ACE_Log_Msg *instance (void);

  /// Returns non-null if an ACE_Log_Msg exists for the calling thread.
  static int exists (void);

  /// Clears the flag from the default priority mask used to
  /// initialize ACE_Log_Msg instances.
  static void disable_debug_messages (ACE_Log_Priority priority = LM_DEBUG);

  /// Sets the flag in the default priority mask used to initialize
  /// ACE_Log_Msg instances.
  static void enable_debug_messages (ACE_Log_Priority priority = LM_DEBUG);

  /// Initialize logger.
  ACE_Log_Msg (void);

  /// cleanup logger.
  ~ACE_Log_Msg (void);

  /// Initialize the ACE logging facility.
  /**
   * Initialize the ACE logging facility. Supplies the program name
   * that is available to each logging message call. Default arguments
   * set up logging to STDERR only.
   *
   * @param prog_name  The name of the calling program.
   * @param flags      A bitwise-or of options flags used to set the
   *                   initial behavior and logging sink(s). (see the
   *                   enum above for the valid values).
   * @param logger_key The name of ACE_FIFO rendezvous point where the
   *                   local client logger daemon is listening for logging
   *                   messages. Only meaningful if the LOGGER bit is
   *                   set in the <flags> argument.
   */
  int open (const ACE_TCHAR *prog_name,
            u_long options_flags = ACE_Log_Msg::STDERR,
            const ACE_TCHAR *logger_key = 0);

  // = Set/get the options flags.

  /**
   * Enable the bits in the logger's options flags.
   * Disable the bits in the logger's options flags.
   * Return the bits in the logger's options flags.
   */
  void set_flags (u_long f);
  void clr_flags (u_long f);
  u_long flags (void);

  /** @name Allow apps to acquire and release internal synchronization
   *        lock
   *
   * This lock is used internally by the <ACE_Log_Msg>
   * implementation. By exporting the lock, applications can hold the
   * lock atomically over a number of calls to <ACE_Log_Msg>.
   */
  //@{

  /// Acquire the internal lock.
  int acquire (void);

  /// Release the internal lock.
  int release (void);
  //@}

  /// Call after doing a <fork> to resynchronize the process id and
  /// <program_name> variables.
  void sync (const ACE_TCHAR *program_name);

  // = Set/get methods.  Note that these are non-static and thus will
  // be thread-specific.

  /// Set the result of the operation status (by convention, -1 means
  /// error).
  void op_status (int status);

  /// Get the result of the operation status (by convention, -1 means
  /// error).
  int op_status (void);

  /// Set the value of the errnum (by convention this corresponds to
  /// errno).
  void errnum (int);

  /// Get the value of the errnum (by convention this corresponds to
  /// errno).
  int errnum (void);

  /// Set the line number where an error occurred.
  void linenum (int);

  /// Get the line number where an error occurred.
  int linenum (void);

  /// Set the file name where an error occurred.
  void file (const char *);

  /// Get the file name where an error occurred.
  const char *file (void);

  /// Set the message that describes what type of error occurred.
  void msg (const ACE_TCHAR *);

  /// Get the message that describes what type of error occurred.
  const ACE_TCHAR *msg (void);

  /// Set the field that indicates whether interrupted calls should be
  /// restarted.
  void restart (int);

  /// Get the field that indicates whether interrupted calls should be
  /// restarted.
  int restart (void);

  // = Notice that the following two function is equivalent to
  //   "void msg_ostream (HANDLE)" and "HANDLE msg_ostream (void)"
  //   on Windows CE.  There is no <iostream.h> support on CE.

  /// Update the ostream without overwriting the delete_ostream_ flag.
  void msg_ostream (ACE_OSTREAM_TYPE *);

  /**
   * delete_stream == 1, forces Log_Msg.h to delete the stream in
   * its own ~dtor (assumes control of the stream)
   * use only with proper ostream (eg: fstream), not (cout, cerr)
   */
  void msg_ostream (ACE_OSTREAM_TYPE *, int delete_ostream);

  /// Get the ostream that is used to print error messages.
  ACE_OSTREAM_TYPE *msg_ostream (void) const;

  /**
   * Set a new callback object and return the existing callback to
   * allow "chaining".  Note that <ACE_Log_Msg_Callback>s are not
   * inherited when spawning a new thread, so you'll need to reset
   * them in each thread.
   */
  ACE_Log_Msg_Callback *msg_callback (ACE_Log_Msg_Callback *c);
  ACE_Log_Msg_Callback *msg_callback (void) const;

  // = Nesting depth increment and decrement.
  int inc (void);
  int dec (void);

  // = Get/set trace depth.
  int trace_depth (void);
  void trace_depth (int);

  // = Get/set trace active status.
  int trace_active (void);
  void trace_active (int value);

  /// Get the TSS thread descriptor.
  ACE_Thread_Descriptor *thr_desc (void) const;

  /**
   * Set the TSS thread descriptor.  This method will call
   * td->acquire_release to block execution until this call
   * return.
   */
  void thr_desc (ACE_Thread_Descriptor *td);

#if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS) && defined(ACE_LEGACY_MODE)
  // These functions are disabled without ACE_LEGACY_MODE
  // because the *semantics* have changed (the objects are no longer
  // TSS).
  /// Get/Set TSS exception action.
  /// NOTE: The action is no longer TSS, they are global!
  ACE_SEH_EXCEPT_HANDLER seh_except_selector (void);
  ACE_SEH_EXCEPT_HANDLER seh_except_selector (ACE_SEH_EXCEPT_HANDLER);

  /// Get/Set TSS exception handler.
  /// NOTE: The handler is no longer TSS, they are global!
  ACE_SEH_EXCEPT_HANDLER seh_except_handler (void);
  ACE_SEH_EXCEPT_HANDLER seh_except_handler (ACE_SEH_EXCEPT_HANDLER);
#endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS && ACE_LEGACY_MODE */

  // = Stop/start/query tracing status on a per-thread basis...
  void stop_tracing (void);
  void start_tracing (void);
  int  tracing_enabled (void);

  typedef enum
  {
    PROCESS = 0,
    THREAD = 1
  } MASK_TYPE;

  // = Get/set the priority mask.
  /// Get the current <ACE_Log_Priority> mask.
  /// Set the <ACE_Log_Priority> mask, returns original mask.
  u_long priority_mask (MASK_TYPE = THREAD);
  u_long priority_mask (u_long, MASK_TYPE = THREAD);

  /// Return true if the requested priority is enabled.
  int log_priority_enabled (ACE_Log_Priority log_priority);

  /// Return true if the requested priority is enabled.
  int log_priority_enabled (ACE_Log_Priority log_priority,
                            const char *,
                            ...);

#if defined (ACE_USES_WCHAR)
  // We are not using ACE_TCHAR for this since ACE_HEX_DUMP
  // doesn't take in a ACE_TCHAR.  log_hexdump takes in a char
  // string, so this must be able to take in a char string even
  // when using ACE_USES_WCHAR.
  /// Return true if the requested priority is enabled.
  int log_priority_enabled (ACE_Log_Priority log_priority,
                            const wchar_t *,
                            ...);
#endif /* ACE_USES_WCHAR */

  /// Optimize reading of the pid (avoids a system call if the value is
  /// cached...).
  pid_t getpid (void) const;

  // = Set/get the name of the local host.
  const ACE_TCHAR *local_host (void) const;
  void local_host (const ACE_TCHAR *);

  /**
   * Set the line number, file name, operational status, error number,
   * restart flag, ostream, and the callback object.  This combines
   * all the other set methods into a single method.
   */
  void set (const char *file,
            int line,
            int op_status = -1,
            int errnum = 0,
            int restart = 1,
            ACE_OSTREAM_TYPE *os = 0,
            ACE_Log_Msg_Callback *c = 0);

  /// These values are only actually set if the requested priority is
  /// enabled.
  void conditional_set (const char *file,
                        int line,
                        int op_status,
                        int errnum);

  /**
   * Format a message to the thread-safe ACE logging mechanism.  Valid
   * options (prefixed by '%', as in printf format strings) include:
   *  + 'A': print an ACE_timer_t value (which could be either double
   *         or ACE_UINT32.)
   *  + 'a': abort the program at this point abruptly.
   *  + 'c': print a character
   *  + 'C': print a character string
   *  + 'i', 'd': print a decimal number
   *  + 'I': indent according to nesting depth (obtained from
   *         <ACE_Trace::get_nesting_indent>).
   *  + 'e', 'E', 'f', 'F', 'g', 'G': print a double
   *  + 'l': print line number where an error occurred.
   *  + 'm': return the message corresponding to errno value, e.g., as
   *         done by strerror()
   *  + 'N': print file name where the error occurred.
   *  + 'n': print the name of the program (or "<unknown>" if not set)
   *  + 'o': print as an octal number
   *  + 'P': print out the current process id
   *  + 'p': print out the appropriate errno message from sys_errlist,
   *         e.g., as done by perror()
   *  + 'Q': print out the uint64 number
   *  + 'r': call the function pointed to by the corresponding argument
   *  + 'R': print return status
   *  + 'S': print out the appropriate _sys_siglist entry corresponding
   *         to var-argument.
   *  + 's': print out a character string
   *  + 'T': print timestamp in hour:minute:sec:usec format.
   *  + 'D': print timestamp in month/day/year hour:minute:sec:usec format.
   *  + 't': print thread id (1 if single-threaded)
   *  + 'u': print as unsigned int
   *  + 'w': prints a wide character
   *  + 'W': print a wide character string
   *  + 'X', 'x': print as a hex number
   *  + '%': print out a single percent sign, '%'
   */
  ssize_t log (ACE_Log_Priority priority, const ACE_TCHAR *format, ...);

#if defined (ACE_HAS_WCHAR)
  ssize_t log (ACE_Log_Priority priority, const ACE_ANTI_TCHAR *format, ...);
#endif /* ACE_HAS_WCHAR */

  /**
   * An alternative logging mechanism that makes it possible to
   * integrate variable argument lists from other logging mechanisms
   * into the ACE mechanism.
   */
  ssize_t log (const ACE_TCHAR *format,
               ACE_Log_Priority priority,
               va_list argp);

  /// Log a custom built log record to the currently enabled logging
  /// sinks.
  ssize_t log (ACE_Log_Record &log_record,
               int suppress_stderr = 0);

  /**
   * Method to log hex dump.  This is useful for debugging.  Calls
   * <log> to do the actual print, but formats first to make the chars
   * printable.
   */
  int log_hexdump (ACE_Log_Priority log_priority,
                   const char *buffer,
                   int size,
                   const ACE_TCHAR *text = 0);

  static void init_hook (ACE_OS_Log_Msg_Attributes &attributes
# if defined (ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS)
                         , ACE_SEH_EXCEPT_HANDLER selector = 0
                         , ACE_SEH_EXCEPT_HANDLER handler = 0
# endif /* ACE_HAS_WIN32_STRUCTURAL_EXCEPTIONS */
  /**
   * Init hook, create a Log_Msg_Attribute object, initialize its
   * attributes from the TSS Log_Msg and save the object in the
   * <attributes> argument
   */
                         );

  /**
   * Inherit hook, the <attributes> field is a Log_Msg_Attribute
   * object, invoke the <inherit_log_msg> method on it, then destroy
   * it and set the <attribute> argument to 0
   */
  static void inherit_hook (ACE_OS_Thread_Descriptor *thr_desc,
                            ACE_OS_Log_Msg_Attributes &attributes);

  /// Dump the state of an object.
  void dump (void) const;

  /// Declare the dynamic allocation hooks.
  ACE_ALLOC_HOOK_DECLARE;

private:
  /// Status of operation (-1 means failure, >= 0 means success).
  int status_;

  /// Type of error that occurred (see <sys/errno.h>).
  int errnum_;

  /// Line number where the error occurred.
  int linenum_;

  /// File where the error occurred.
  char file_[MAXPATHLEN + 1];

  /// The log message, which resides in thread-specific storage.  Note
  /// that only the current log message is stored here -- it will be
  /// overwritten by the subsequent call to <log>.
  ACE_TCHAR msg_[ACE_Log_Record::MAXLOGMSGLEN];

  /// Indicates whether we should restart system calls that are
  /// interrupted.
  int restart_;

  /// The ostream where logging messages can be written.
  ACE_OSTREAM_TYPE *ostream_;

  /// The callback object.
  ACE_Log_Msg_Callback *msg_callback_;

  /// Depth of the nesting for printing traces.
  int trace_depth_;

  /// Are we already within an ACE_Trace constructor call?
  int trace_active_;

  /// Are we allowing tracing in this thread?
  int tracing_enabled_;

  /// Are we deleting this ostream?
  int delete_ostream_;

  /**
   * If we're running in the context of an <ACE_Thread_Manager> this
   * will point to the thread descriptor adapter which holds the
   * thread descriptor of the thread.  This can be used to repidly
   * access all thread data kept in <ACE_Thread_Descriptor>.
   */
  ACE_Thread_Descriptor *thr_desc_;

  /**
   * Keeps track of all the per-thread <ACE_Log_Priority> values that
   * are currently enabled.  Default is for all logging priorities to
   * be _disabled_.
   */
  u_long priority_mask_;

  // = The following fields are *not* kept in thread-specific storage.

  // We only want one instance for the entire process!

  /**
   * Keeps track of all the per-process <ACE_Log_Priority> values that
   * are currently enabled.  Default is for all logging priorities to
   * be enabled.
   */
  static u_long process_priority_mask_;

  /// Records the program name.
  static const ACE_TCHAR *program_name_;

  /// Name of the local host (used when printing messages).
  static const ACE_TCHAR *local_host_;

  /// Process id of the current process.
  static pid_t pid_;

  /// Options flags.
  static u_long flags_;

  /// Offset of msg_[].
  static int msg_off_;

  /**
   * Number of existing Log_Msg instances; when 0, delete program/host
   * names
   * Priority mask to use for each new instance
   */
  static int instance_count_;
  static u_long default_priority_mask_;

  // Anonymous struct since there will only be one instance.  This
  // struct keeps information stored away in case we actually end up
  // calling log() if the log priority is correct.
  struct
  {
    int is_set_;
    const char *file_;
    int line_;
    int op_status_;
    int errnum_;
  } conditional_values_;

#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
  static int key_created_;
# if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || \
    defined (ACE_HAS_TSS_EMULATION)
  static ACE_thread_key_t log_msg_tss_key_;
# endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION */
#endif /* ACE_MT_SAFE */

  /// For cleanup, at program termination.
  static void close (void);

  /// Decouple the OS layer from the Log_Msg layer.
  static void sync_hook (const ACE_TCHAR *prg_name);

  /// Return the TSS singleton thread descriptor
  static ACE_OS_Thread_Descriptor *thr_desc_hook (void);

  friend void ACE_OS::cleanup_tss (const u_int);

  // = Disallow these operations.
  ACE_Log_Msg &operator= (const ACE_Log_Msg &);
  ACE_Log_Msg (const ACE_Log_Msg &);
};

#if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
# if defined (ACE_HAS_THREAD_SPECIFIC_STORAGE) || \
     defined (ACE_HAS_TSS_EMULATION)
/* static */
#  if defined (ACE_HAS_THR_C_DEST)
#   define LOCAL_EXTERN_PREFIX extern "C"
#  else
#   define LOCAL_EXTERN_PREFIX
#  endif /* ACE_HAS_THR_C_DEST */
LOCAL_EXTERN_PREFIX
void
ACE_TSS_cleanup (void *ptr);
# endif /* ACE_HAS_THREAD_SPECIFIC_STORAGE || ACE_HAS_TSS_EMULATION */
#endif /* ACE_MT_SAFE */

#if defined (ACE_THREAD_HACK)
#define THREAD ACE_THREAD_HACK
#undef ACE_THREAD_HACK
#endif /* ACE_THREAD_HACK */

#if defined(ACE_LEGACY_MODE)
#include "ace/Log_Msg_Callback.h"
#endif /* ACE_LEGACY_MODE */

#include "ace/post.h"
#endif /* ACE_LOG_MSG_H */