Changes to attempt to silence bcc64x
[ACE_TAO.git] / ACE / ace / Logging_Strategy.cpp
blob7b3335e39fa83eb995842127dbf5321dc2656110
1 #include "ace/Logging_Strategy.h"
2 #include "ace/Service_Config.h"
3 #include "ace/ACE.h"
4 #include "ace/ACE_export.h"
5 #include "ace/Get_Opt.h"
7 // FUZZ: disable check_for_streams_include
8 #include "ace/streams.h"
10 #include "ace/Lib_Find.h"
11 #include "ace/Log_Category.h"
12 #include "ace/Reactor.h"
13 #include "ace/OS_NS_string.h"
14 #include "ace/OS_NS_stdio.h"
15 #include "ace/OS_NS_unistd.h"
17 ACE_BEGIN_VERSIONED_NAMESPACE_DECL
19 // Parse the string containing (thread) priorities and set them
20 // accordingly.
22 void
23 ACE_Logging_Strategy::priorities (ACE_TCHAR *priority_string,
24 ACE_Log_Msg::MASK_TYPE mask)
26 u_long priority_mask = 0;
28 // Choose priority mask to change.
30 if (mask == ACE_Log_Msg::PROCESS)
31 priority_mask = process_priority_mask_;
32 else
33 priority_mask = thread_priority_mask_;
35 ACE_TCHAR *strtokp = 0;
37 // Parse string and alternate priority mask.
39 for (ACE_TCHAR *priority = ACE_OS::strtok_r (priority_string,
40 ACE_TEXT ("|"),
41 &strtokp);
42 priority != 0;
43 priority = ACE_OS::strtok_r (0,
44 ACE_TEXT ("|"),
45 &strtokp))
47 if (ACE_OS::strcmp (priority, ACE_TEXT ("SHUTDOWN")) == 0)
48 ACE_SET_BITS (priority_mask, LM_SHUTDOWN);
49 else if (ACE_OS::strcmp (priority, ACE_TEXT ("~SHUTDOWN")) == 0)
50 ACE_CLR_BITS (priority_mask, LM_SHUTDOWN);
51 else if (ACE_OS::strcmp (priority, ACE_TEXT ("TRACE")) == 0)
52 ACE_SET_BITS (priority_mask, LM_TRACE);
53 else if (ACE_OS::strcmp (priority, ACE_TEXT ("~TRACE")) == 0)
54 ACE_CLR_BITS (priority_mask, LM_TRACE);
55 else if (ACE_OS::strcmp (priority, ACE_TEXT ("DEBUG")) == 0)
56 ACE_SET_BITS (priority_mask, LM_DEBUG);
57 else if (ACE_OS::strcmp (priority, ACE_TEXT ("~DEBUG")) == 0)
58 ACE_CLR_BITS (priority_mask, LM_DEBUG);
59 else if (ACE_OS::strcmp (priority, ACE_TEXT ("INFO")) == 0)
60 ACE_SET_BITS (priority_mask, LM_INFO);
61 else if (ACE_OS::strcmp (priority, ACE_TEXT ("~INFO")) == 0)
62 ACE_CLR_BITS (priority_mask, LM_INFO);
63 else if (ACE_OS::strcmp (priority, ACE_TEXT ("NOTICE")) == 0)
64 ACE_SET_BITS (priority_mask, LM_NOTICE);
65 else if (ACE_OS::strcmp (priority, ACE_TEXT ("~NOTICE")) == 0)
66 ACE_CLR_BITS (priority_mask, LM_NOTICE);
67 else if (ACE_OS::strcmp (priority, ACE_TEXT ("WARNING")) == 0)
68 ACE_SET_BITS (priority_mask, LM_WARNING);
69 else if (ACE_OS::strcmp (priority, ACE_TEXT ("~WARNING")) == 0)
70 ACE_CLR_BITS (priority_mask, LM_WARNING);
71 else if (ACE_OS::strcmp (priority, ACE_TEXT ("STARTUP")) == 0)
72 ACE_SET_BITS (priority_mask, LM_STARTUP);
73 else if (ACE_OS::strcmp (priority, ACE_TEXT ("~STARTUP")) == 0)
74 ACE_CLR_BITS (priority_mask, LM_STARTUP);
75 else if (ACE_OS::strcmp (priority, ACE_TEXT ("ERROR")) == 0)
76 ACE_SET_BITS (priority_mask, LM_ERROR);
77 else if (ACE_OS::strcmp (priority, ACE_TEXT ("~ERROR")) == 0)
78 ACE_CLR_BITS (priority_mask, LM_ERROR);
79 else if (ACE_OS::strcmp (priority, ACE_TEXT ("CRITICAL")) == 0)
80 ACE_SET_BITS (priority_mask, LM_CRITICAL);
81 else if (ACE_OS::strcmp (priority, ACE_TEXT ("~CRITICAL")) == 0)
82 ACE_CLR_BITS (priority_mask, LM_CRITICAL);
83 else if (ACE_OS::strcmp (priority, ACE_TEXT ("ALERT")) == 0)
84 ACE_SET_BITS (priority_mask, LM_ALERT);
85 else if (ACE_OS::strcmp (priority, ACE_TEXT ("~ALERT")) == 0)
86 ACE_CLR_BITS (priority_mask, LM_ALERT);
87 else if (ACE_OS::strcmp (priority, ACE_TEXT ("EMERGENCY")) == 0)
88 ACE_SET_BITS (priority_mask, LM_EMERGENCY);
89 else if (ACE_OS::strcmp (priority, ACE_TEXT ("~EMERGENCY")) == 0)
90 ACE_CLR_BITS (priority_mask, LM_EMERGENCY);
93 // Affect right priority mask.
95 if (mask == ACE_Log_Msg::PROCESS)
96 process_priority_mask_ = priority_mask;
97 else
98 thread_priority_mask_ = priority_mask;
101 // Parse the string containing all the flags and set the flags
102 // accordingly.
104 void
105 ACE_Logging_Strategy::tokenize (ACE_TCHAR *flag_string)
107 ACE_TCHAR *strtokp;
109 for (ACE_TCHAR *flag = ACE_OS::strtok_r (flag_string,
110 ACE_TEXT ("|"),
111 &strtokp);
112 flag != 0;
113 flag = ACE_OS::strtok_r (0, ACE_TEXT ("|"), &strtokp))
115 if (ACE_OS::strcmp (flag, ACE_TEXT ("STDERR")) == 0)
116 ACE_SET_BITS (this->flags_, ACE_Log_Msg::STDERR);
117 else if (ACE_OS::strcmp (flag, ACE_TEXT ("LOGGER")) == 0)
118 ACE_SET_BITS (this->flags_, ACE_Log_Msg::LOGGER);
119 else if (ACE_OS::strcmp (flag, ACE_TEXT ("OSTREAM")) == 0)
120 ACE_SET_BITS (this->flags_, ACE_Log_Msg::OSTREAM);
121 else if (ACE_OS::strcmp (flag, ACE_TEXT ("VERBOSE")) == 0)
122 ACE_SET_BITS (this->flags_, ACE_Log_Msg::VERBOSE);
123 else if (ACE_OS::strcmp (flag, ACE_TEXT ("VERBOSE_LITE")) == 0)
124 ACE_SET_BITS (this->flags_, ACE_Log_Msg::VERBOSE_LITE);
125 else if (ACE_OS::strcmp (flag, ACE_TEXT ("SILENT")) == 0)
126 ACE_SET_BITS (this->flags_, ACE_Log_Msg::SILENT);
127 else if (ACE_OS::strcmp (flag, ACE_TEXT ("SYSLOG")) == 0)
128 ACE_SET_BITS (this->flags_, ACE_Log_Msg::SYSLOG);
133 ACE_Logging_Strategy::parse_args (int argc, ACE_TCHAR *argv[])
135 ACE_TRACE ("ACE_Logging_Strategy::parse_args");
136 ACE_TCHAR *temp;
138 // Perform data member initializations. BTW, do *not* initialize
139 // <thread_priority_mask_> or <process_priority_mask_> here to avoid
140 // unduing the behavior in <init>, where these are set by
141 // <ACE_Log_Msg::instance>.
142 this->flags_ = 0;
143 this->wipeout_logfile_ = false;
144 this->count_ = 0;
145 this->fixed_number_ = false;
146 this->order_files_ = false;
147 this->max_file_number_ = 1;
148 this->interval_ = ACE_DEFAULT_LOGFILE_POLL_INTERVAL;
149 this->max_size_ = 0;
151 ACE_Get_Opt get_opt (argc, argv,
152 ACE_TEXT ("f:i:k:m:n:N:op:s:t:w"), 0);
154 for (int c; (c = get_opt ()) != -1; )
156 switch (c)
158 case 'f':
159 temp = get_opt.opt_arg ();
160 // Now tokenize the string to get all the flags
161 this->tokenize (temp);
162 // If LOGGER was specified, set up the default logger key.
163 // The key can be changed by the -k option also, so if it's
164 // been set already, don't set it.
165 if (ACE_BIT_ENABLED (this->flags_, ACE_Log_Msg::LOGGER) &&
166 this->logger_key_ == 0)
167 this->logger_key_ = ACE::strnew (ACE_DEFAULT_LOGGER_KEY);
168 break;
169 case 'i':
170 // Interval (in secs) at which logfile size is sampled.
171 this->interval_ = ACE_OS::strtoul (get_opt.opt_arg (), 0, 10);
172 break;
173 case 'k':
174 // Ensure that the LOGGER flag is set
175 ACE_SET_BITS (this->flags_, ACE_Log_Msg::LOGGER);
176 #if defined (ACE_HAS_ALLOC_HOOKS)
177 ACE_Allocator::instance()->free(this->logger_key_);
178 #else
179 delete [] this->logger_key_;
180 #endif /* ACE_HAS_ALLOC_HOOKS */
181 this->logger_key_ = ACE::strnew (get_opt.opt_arg ());
182 break;
183 case 'm':
184 // Maximum logfile size (in KB). Must be a non-zero value.
185 this->max_size_ = ACE_OS::strtoul (get_opt.opt_arg (), 0, 10);
186 this->max_size_ <<= 10; // convert from KB to bytes.
187 break;
188 case 'n':
189 #if defined (ACE_HAS_ALLOC_HOOKS)
190 ACE_Allocator::instance()->free(this->program_name_);
191 #else
192 delete [] this->program_name_;
193 #endif /* ACE_HAS_ALLOC_HOOKS */
194 this->program_name_ = ACE::strnew (get_opt.opt_arg ());
195 break;
196 case 'N':
197 // The max number for the log_file being created
198 this->max_file_number_ = ACE_OS::atoi (get_opt.opt_arg ()) - 1;
199 this->fixed_number_ = true;
200 break;
201 case 'o':
202 // Log_files generation order
203 this->order_files_ = true;
204 break;
205 case 'p':
206 temp = get_opt.opt_arg ();
207 // Now tokenize the string to setup process log priority
208 this->priorities (temp, ACE_Log_Msg::PROCESS);
209 break;
210 case 's':
211 // Ensure that the OSTREAM flag is set
212 ACE_SET_BITS (this->flags_, ACE_Log_Msg::OSTREAM);
213 #if defined (ACE_HAS_ALLOC_HOOKS)
214 ACE_Allocator::instance()->free(this->filename_);
215 #else
216 delete [] this->filename_;
217 #endif /* ACE_HAS_ALLOC_HOOKS */
218 this->filename_ = ACE::strnew (get_opt.opt_arg ());
219 break;
220 case 't':
221 temp = get_opt.opt_arg ();
222 // Now tokenize the string to setup thread log priority
223 this->priorities (temp, ACE_Log_Msg::THREAD);
224 break;
225 case 'w':
226 // Cause the logfile to be wiped out, both on startup and on
227 // reconfigure.
228 this->wipeout_logfile_ = true;
229 break;
230 default:
231 break;
234 return 0;
237 ACE_Logging_Strategy::ACE_Logging_Strategy ()
238 : thread_priority_mask_ (0),
239 process_priority_mask_ (0),
240 flags_ (0),
241 filename_ (0),
242 logger_key_ (0),
243 program_name_ (0),
244 wipeout_logfile_ (false),
245 fixed_number_ (false),
246 order_files_ (false),
247 count_ (0),
248 max_file_number_ (1), // 2 files by default (max file number + 1)
249 interval_ (ACE_DEFAULT_LOGFILE_POLL_INTERVAL),
250 max_size_ (0),
251 log_msg_ (ACE_Log_Msg::instance ())
253 #if defined (ACE_DEFAULT_LOGFILE)
254 this->filename_ = ACE::strnew (ACE_DEFAULT_LOGFILE);
255 #else /* ACE_DEFAULT_LOGFILE */
256 #if defined (ACE_HAS_ALLOC_HOOKS)
257 ACE_ALLOCATOR (this->filename_,
258 static_cast<ACE_TCHAR *>(ACE_Allocator::instance()->malloc(sizeof(ACE_TCHAR) * (MAXPATHLEN + 1))));
259 #else
260 ACE_NEW (this->filename_,
261 ACE_TCHAR[MAXPATHLEN + 1]);
262 #endif /* ACE_HAS_ALLOC_HOOKS */
264 // Get the temporary directory
265 if (ACE::get_temp_dir
266 (this->filename_,
267 MAXPATHLEN - 7) == -1) // 7 for "logfile"
269 ACELIB_ERROR ((LM_ERROR,
270 ACE_TEXT ("Temporary path too long, ")
271 ACE_TEXT ("defaulting to current directory\n")));
272 this->filename_[0] = 0;
275 // Add the filename to the end
276 ACE_OS::strcat (this->filename_,
277 ACE_TEXT ("logfile"));
278 #endif /* ACE_DEFAULT_LOGFILE */
281 ACE_Logging_Strategy::~ACE_Logging_Strategy ()
283 // This is allocated in constructor, so it must be deallocated in
284 // the destructor!
285 #if defined (ACE_HAS_ALLOC_HOOKS)
286 ACE_Allocator::instance()->free(this->filename_);
287 #else
288 delete [] this->filename_;
289 #endif /* ACE_HAS_ALLOC_HOOKS */
293 ACE_Logging_Strategy::fini ()
295 #if defined (ACE_HAS_ALLOC_HOOKS)
296 ACE_Allocator::instance()->free(this->filename_);
297 #else
298 delete [] this->filename_;
299 #endif /* ACE_HAS_ALLOC_HOOKS */
300 this->filename_ = 0; // Avoid double deletions.
302 #if defined (ACE_HAS_ALLOC_HOOKS)
303 ACE_Allocator::instance()->free(this->logger_key_);
304 ACE_Allocator::instance()->free(this->program_name_);
305 #else
306 delete [] this->logger_key_;
307 delete [] this->program_name_;
308 #endif /* ACE_HAS_ALLOC_HOOKS */
310 if (this->reactor ()
311 && this->interval_ > 0 && this->max_size_ > 0)
312 this->reactor ()->cancel_timer (this);
314 return 0;
318 ACE_Logging_Strategy::init (int argc, ACE_TCHAR *argv[])
320 ACE_TRACE ("ACE_Logging_Strategy::init");
322 // Store current priority masks for changes in <parse_args>.
324 this->process_priority_mask_ =
325 this->log_msg_->priority_mask (ACE_Log_Msg::PROCESS);
327 this->thread_priority_mask_ =
328 this->log_msg_->priority_mask (ACE_Log_Msg::THREAD);
330 // Use the options hook to parse the command line arguments.
331 this->parse_args (argc, argv);
333 // Setup priorities (to original if not specified on command line)
335 this->log_msg_->priority_mask (thread_priority_mask_,
336 ACE_Log_Msg::THREAD);
338 this->log_msg_->priority_mask (process_priority_mask_,
339 ACE_Log_Msg::PROCESS);
341 // Check if any flags were specified. If none were specified, let
342 // the default behavior take effect.
343 if (this->flags_ != 0)
345 // Clear all flags
346 this->log_msg_->clr_flags (ACE_Log_Msg::STDERR
347 | ACE_Log_Msg::LOGGER
348 | ACE_Log_Msg::OSTREAM
349 | ACE_Log_Msg::VERBOSE
350 | ACE_Log_Msg::VERBOSE_LITE
351 | ACE_Log_Msg::SILENT
352 | ACE_Log_Msg::SYSLOG);
353 // Check if OSTREAM bit is set
354 if (ACE_BIT_ENABLED (this->flags_,
355 ACE_Log_Msg::OSTREAM))
357 int delete_ostream = 0;
358 #if defined (ACE_LACKS_IOSTREAM_TOTALLY)
359 FILE *output_file = this->log_msg_->msg_ostream ();
360 if (wipeout_logfile_)
362 // close and re-open a stream if such exits
363 if (output_file &&
364 ACE_OS::fclose (output_file) == -1)
365 return -1;
366 output_file = ACE_OS::fopen (this->filename_, ACE_TEXT ("wt"));
368 // open a stream only if such doesn't exists
369 else if (output_file == 0)
370 output_file = ACE_OS::fopen (this->filename_,
371 ACE_TEXT ("at"));
373 if (output_file == 0)
374 return -1;
375 #else
376 ostream *output_file = this->log_msg_->msg_ostream ();
377 // Create a new ofstream to direct output to the file.
378 if (wipeout_logfile_)
380 ACE_NEW_RETURN
381 (output_file,
382 ofstream (ACE_TEXT_ALWAYS_CHAR (this->filename_)),
383 -1);
384 delete_ostream = 1;
386 else if (output_file == 0)
388 ACE_NEW_RETURN
389 (output_file,
390 ofstream (ACE_TEXT_ALWAYS_CHAR (this->filename_),
391 ios::app | ios::out),
392 -1);
393 delete_ostream = 1;
396 if (output_file->rdstate () != ios::goodbit)
398 if (delete_ostream)
399 delete output_file;
400 return -1;
402 #endif /* ACE_LACKS_IOSTREAM_TOTALLY */
403 // Set the <output_file> that'll be used by the rest of the
404 // code.
405 this->log_msg_->msg_ostream (output_file, delete_ostream);
407 // Setup a timeout handler to perform the maximum file size
408 // check (if required).
409 if (this->interval_ > 0 && this->max_size_ > 0)
411 if (this->reactor () == 0)
412 // Use singleton.
413 this->reactor (ACE_Reactor::instance ());
416 // Now set the flags for Log_Msg
417 this->log_msg_->set_flags (this->flags_);
420 return this->log_msg_->open (this->program_name_,
421 this->log_msg_->flags (),
422 this->logger_key_);
426 ACE_Logging_Strategy::handle_timeout (const ACE_Time_Value &,
427 const void *)
429 #if defined (ACE_LACKS_IOSTREAM_TOTALLY)
430 if ((size_t) ACE_OS::ftell (this->log_msg_->msg_ostream ()) > this->max_size_)
431 #else
432 if ((size_t) this->log_msg_->msg_ostream ()->tellp () > this->max_size_)
433 #endif /* ACE_LACKS_IOSTREAM_TOTALLY */
435 // Lock out any other logging.
436 if (this->log_msg_->acquire ())
437 ACELIB_ERROR_RETURN ((LM_ERROR,
438 ACE_TEXT ("Cannot acquire lock!\n")),
439 -1);
441 // Close the current ostream.
442 #if defined (ACE_LACKS_IOSTREAM_TOTALLY)
443 FILE *output_file = (FILE *) this->log_msg_->msg_ostream ();
444 ACE_OS::fclose (output_file);
445 // We'll call msg_ostream() modifier later.
446 #else
447 ofstream *output_file =
448 (ofstream *) this->log_msg_->msg_ostream ();
449 output_file->close ();
450 #endif /* ACE_LACKS_IOSTREAM_TOTALLY */
451 // Save current logfile to logfile.old analyze if it was set any
452 // fixed number for the log_files.
453 if (fixed_number_)
455 if (max_file_number_ < 1) //we only want one file
457 // Just unlink the file.
458 ACE_OS::unlink (this->filename_);
460 // Open a new log file with the same name.
461 #if defined (ACE_LACKS_IOSTREAM_TOTALLY)
462 output_file = ACE_OS::fopen (this->filename_,
463 ACE_TEXT ("wt"));
465 if (output_file == 0)
466 return -1;
468 this->log_msg_->msg_ostream (output_file);
469 #else
470 output_file->open (ACE_TEXT_ALWAYS_CHAR (this->filename_),
471 ios::out);
472 #endif /* ACE_LACKS_IOSTREAM_TOTALLY */
474 // Release the lock previously acquired.
475 this->log_msg_->release ();
476 return 0;
479 count_++;
481 // Set the number of digits of the log_files labels.
482 int digits = 1, res = count_;
483 while((res = (res / 10))>0)
484 digits++;
486 if (ACE_OS::strlen (this->filename_) + digits <= MAXPATHLEN)
488 ACE_TCHAR backup[MAXPATHLEN+1];
490 // analyse if it was chosen the mode which will order the
491 // log_files
492 if (order_files_)
494 ACE_TCHAR to_backup[MAXPATHLEN+1];
496 // reorder the logs starting at the oldest (the biggest
497 // number) watch if we reached max_file_number_.
498 int max_num;
499 if (fixed_number_ && count_ > max_file_number_)
500 // count_ will always be bigger than max_file_number_,
501 // so do nothing so to always reorder files from
502 // max_file_number_.
503 max_num = max_file_number_;
504 else
505 max_num = count_;
507 for (int i = max_num ; i > 1 ;i--)
509 ACE_OS::snprintf (backup, MAXPATHLEN + 1,
510 ACE_TEXT ("%s.%d"),
511 this->filename_,
513 ACE_OS::snprintf (to_backup, MAXPATHLEN + 1,
514 ACE_TEXT ("%s.%d"),
515 this->filename_,
516 i - 1);
518 // Remove any existing old file; ignore error as
519 // file may not exist.
520 ACE_OS::unlink (backup);
522 // Rename the current log file to the name of the
523 // backup log file.
524 ACE_OS::rename (to_backup, backup);
526 ACE_OS::snprintf (backup, MAXPATHLEN + 1,
527 ACE_TEXT ("%s.1"),
528 this->filename_);
530 else
532 if (fixed_number_ && count_>max_file_number_)
533 count_ = 1; // start over from 1
535 ACE_OS::snprintf (backup, MAXPATHLEN + 1,
536 ACE_TEXT ("%s.%d"),
537 this->filename_,
538 count_);
541 // Remove any existing old file; ignore error as file may
542 // not exist.
543 ACE_OS::unlink (backup);
545 // Rename the current log file to the name of the backup log
546 // file.
547 ACE_OS::rename (this->filename_, backup);
549 else
550 ACELIB_ERROR ((LM_ERROR,
551 ACE_TEXT ("Backup file name too long; ")
552 ACE_TEXT ("backup logfile not saved.\n")));
554 // Open a new log file by the same name
555 #if defined (ACE_LACKS_IOSTREAM_TOTALLY)
556 output_file = ACE_OS::fopen (this->filename_, ACE_TEXT ("wt"));
558 if (output_file == 0)
559 return -1;
561 this->log_msg_->msg_ostream (output_file);
562 #else
563 output_file->open (ACE_TEXT_ALWAYS_CHAR (this->filename_),
564 ios::out);
565 #endif /* ACE_LACKS_IOSTREAM_TOTALLY */
567 // Release the lock previously acquired.
568 this->log_msg_->release ();
571 return 0;
575 ACE_Logging_Strategy::handle_close (ACE_HANDLE,
576 ACE_Reactor_Mask)
578 // This will reset reactor member and cancel timer events.
579 this->reactor (0);
580 return 0;
583 void
584 ACE_Logging_Strategy::reactor (ACE_Reactor *r)
586 if (this->reactor () != r)
588 if (this->reactor () && this->interval_ > 0 && this->max_size_ > 0)
590 this->reactor ()->cancel_timer (this);
593 ACE_Service_Object::reactor (r);
595 if (this->reactor ())
597 this->reactor ()->schedule_timer
598 (this, 0,
599 ACE_Time_Value (this->interval_),
600 ACE_Time_Value (this->interval_));
605 ACE_Reactor *
606 ACE_Logging_Strategy::reactor () const
608 return ACE_Service_Object::reactor ();
611 void
612 ACE_Logging_Strategy::log_msg (ACE_Log_Msg *log_msg)
614 this->log_msg_ = log_msg;
617 // The following is a "Factory" used by the ACE_Service_Config and
618 // svc.conf file to dynamically initialize the state of the
619 // Logging_Strategy.
621 ACE_STATIC_SVC_DEFINE (ACE_Logging_Strategy,
622 ACE_TEXT ("Logging_Strategy"),
623 ACE_Service_Type::SERVICE_OBJECT,
624 &ACE_SVC_NAME (ACE_Logging_Strategy),
625 ACE_Service_Type::DELETE_THIS | ACE_Service_Type::DELETE_OBJ,
628 ACE_FACTORY_DEFINE (ACE, ACE_Logging_Strategy)
630 ACE_END_VERSIONED_NAMESPACE_DECL
632 // _get_dll_unload_policy() prevents ACE from being unloaded and having its
633 // framework components run down if/when the Logging Strategy is unloaded.
634 extern "C" ACE_Export int
635 _get_dll_unload_policy()
637 return ACE_DLL_UNLOAD_POLICY_LAZY;